5

これがvb.netで見つけた、理解できない小さなものです。ツリービューが表示されたフォームがあり、次のようになっています。

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

テストは拡張メソッドです。

Imports System.Runtime.CompilerServices
Public Module ExtModule
    <Extension()>
    Public Sub Test(ByRef node As TreeNode)
    End Sub
End Module

ByRefを使用すると、ツリービューは次のようになります。

http://i.imgur.com/nQk0s.png

そしてByValで私は得ます:

http://i.imgur.com/n2ZSf.png

これは完全に逆のように見えます。単に参照を送信している場合、ノードが2回表示されるのに、コピーを作成すると1回しか表示されないのはなぜですか。

4

2 に答える 2

6

さて、私は何が起こっているのを理解しました。

拡張メソッド自体とはほとんど関係がありません。それは、VBが一般的にどのように処理するか、そしてその外観によるByRefいくつかの奇妙な振る舞いについてです。TreeView.Nodes

特に、これを変更すると、まったく同じ動作が得られます。

treeTest.Nodes(0).Test()

に:

ExtModule.Test(treeTest.Nodes(0))

...削除してもExtensionAttribute

refパラメータや拡張メソッドをまったく使用せずに、同じ効果を示すC#コードを次に示します。

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);
    }
}

重要な行は次のとおりです。

TreeNode node = tree.Nodes[0];
tree.Nodes[0] = node;

空の拡張メソッドにByRefパラメーターがある場合、コードは上記のC#コードと同等です。これは、VBが一時変数を使用して「実際の」ByRef動作を偽造し、元のプロパティに割り当てるためです。

空の拡張メソッドにByValパラメーターがある場合、コードは次のようになります。

TreeNode node = tree.Nodes[0];
// Do nothing

...そしてそれは2番目のノードを作成しません。

于 2012-11-21T14:46:27.463 に答える
2

小さなVBの例をコンパイルし、Reflectorを使用してC#コードとして逆コンパイルしました。これは私が得たものです:

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;

コンパイルされません。したがって、私は別のテストを行いました

treeView1.Nodes.Add("a");
treeView1.Nodes[0] = treeView1.Nodes[0];
treeView1.Nodes[0] = treeView1.Nodes[0];
treeView1.Nodes[0] = treeView1.Nodes[0];

コレクションへの各割り当てはNodes、ノードを視覚的に複製します。ただし、ノード数は残り1ます。これは明らかにの動作のエラーですTreeView

注:どうやらVBでは、拡張メソッドの最初のパラメーターを参照することができます。これは厄介で、予期しない動作を引き起こす可能性があります。私のアドバイス:ByRefここでは使用しないでください!

于 2012-11-21T15:09:43.593 に答える