Here's a little something I discovered in vb.net which I cannot figure out, I've just got a form with a treeview on it and then the following:
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
treeTest.Nodes.Add("a")
treeTest.Nodes(0).Test()
End Sub
Test is an extension method:
Imports System.Runtime.CompilerServices
Public Module ExtModule
<Extension()>
Public Sub Test(ByRef node As TreeNode)
End Sub
End Module
If I use ByRef then my treeview looks like:
And with ByVal I get:
This seems totally backwards, if I'm simply sending a reference why is the node appearing twice, while if I make a copy it only appears once?
Okay, I've worked out some of what's going on.
It's got relatively little to do with extension methods per se. It's more about how VB handles ByRef
in general, and some odd behaviour of TreeView.Nodes
by the looks of it.
In particular, you'll get the exact same behaviour if you change this:
treeTest.Nodes(0).Test()
to:
ExtModule.Test(treeTest.Nodes(0))
... even if you remove the ExtensionAttribute
.
Here's some C# code which demonstrates the same effect, without using ref
parameters or extension methods at all:
using System.Drawing;
using System.Windows.Forms;
class Test
{
static void Main()
{
TreeView tree = new TreeView { Nodes = { "a" } };
Form form = new Form { Controls = { tree } };
form.Load += delegate {
TreeNode node = tree.Nodes[0];
tree.Nodes[0] = node;
};
Application.Run(form);
}
}
The important lines are these ones:
TreeNode node = tree.Nodes[0];
tree.Nodes[0] = node;
When your empty extension method has a ByRef
parameter, your code is equivalent to the above C# code - because VB fakes "real" ByRef
behaviour by using a temporary variable and then assigning back to the original property.
When your empty extension method has a ByVal
parameter, your code is just equivalent to:
TreeNode node = tree.Nodes[0];
// Do nothing
... and that doesn't create a second node.
I compiled a little VB example and decompiled it as C# code with Reflector. This is what I got:
treeView.Nodes.Add("a");
TreeNodeCollection VB$t_ref$S0 = treeView.Nodes;
int VB$t_i4$S0 = 0;
TreeNode VB$t_ref$S1 = VB$t_ref$S0[VB$t_i4$S0];
ref VB$t_ref$S1.Test();
VB$t_ref$S0[VB$t_i4$S0] = VB$t_ref$S1;
It does not compile. Therefore I did another test
treeView1.Nodes.Add("a");
treeView1.Nodes[0] = treeView1.Nodes[0];
treeView1.Nodes[0] = treeView1.Nodes[0];
treeView1.Nodes[0] = treeView1.Nodes[0];
Each assignment to the Nodes
collection duplicates the node visually; however, the node count remains 1
. This is clearly an error in the behavior of TreeView
.
Note: Apparently VB allows the first parameter of an extension method to be by reference. This is awkward and can lead to much unexpected behavior. My advice: Don't use ByRef
here!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With