4

ほんの少し前に、以下が合法であることを発見してショックを受けました (C# の同等物は間違いなく合法ではありません)。

Class Assigner
    ''// Ignore this for now.
    Public Field As Integer

    ''// This part is not so weird... take another instance ByRef,
    ''// assign it to a different instance -- stupid but whatever. '
    Sub Assign(ByRef x As Assigner, ByVal y As Assigner)
        x = y
    End Sub

    ''// But... what's this?!?
    Sub AssignNew()
        ''// Passing "Me" ByRef???
        Assign(Me, New Assigner)
    End Sub

    ''// This is just for testing.
    Function GetField() As Integer
        Return Me.Field
    End Function
End Class

しかし、私にとってさらに奇妙なのは、私が期待することをしていないように見えることです。

Dim a As New Assigner With {.Field = 10}

a.AssignNew()

Console.WriteLine(a.GetField())

上記の出力は、私が思っていたような「0」ではなく、「10」を出力します (もちろん、この期待自体にある種の恐怖が吹き込まれていました)。したがって、を渡すことができるMe ByRefように見えますが、動作はコンパイラによって何らかの形でオーバーライド (?) され、を渡したMe ByValのようになります。

  1. なぜ渡すことが合法なのMe ByRefですか?(下位互換性の説明はありますか?)
  2. これを行う動作はコンパイラによってオーバーライドされるというのは正しいですか? そうでない場合、何が欠けていますか?
4

4 に答える 4

5

コンパイラが「Me」を変数に変換し、ByRef に渡すようです。コードをコンパイルして Reflector で開くと、何が起こっているかがわかります。

Class Assigner
    ''// Methods
    Public Sub Assign(ByRef x As Assigner, ByVal y As Assigner)
        x = y
    End Sub

    Public Sub AssignNew()
        Dim VB$t_ref$S0 As Assigner = Me
        Me.Assign((VB$t_ref$S0), New Assigner)
    End Sub

    Public Function GetField() As Integer
        Return Me.Field
    End Function


    ''// Fields
    Public Field As Integer
End Class

したがって、AssignNew() を呼び出すと、内部で生成された変数に新しいインスタンスを割り当てているように見えます。「a」変数は、関数の一部でさえないため、触れられません。

于 2010-10-05T13:19:19.907 に答える
5

この動作は、実際には Visual Basic 仕様にかなり直接的に従っています。

11.4.3 インスタンス式

インスタンス式はキーワードMeMyClass、またはMyBaseです。非共有メソッド、コンストラクター、またはプロパティ アクセサーの本体内でのみ使用できるインスタンス式は、として分類されます。

9.2.5.2 参照パラメータ

参照パラメーターに渡される変数の型が参照パラメーターの型と互換性がない場合、または非変数が引数として参照パラメーターに渡される場合、一時変数が割り当てられ、参照パラメーターに渡されることがあります。渡される値は、メソッドが呼び出される前にこの一時変数にコピーされ、メソッドが戻るときに元の変数(存在する場合)にコピーされます。

(すべて強調私)

そのため、コンパイラはMe、パラメータとして渡される値に割り当てられた一時変数を作成しByRefます。は変数ではないため、返されたときに結果の値のコピーは行われMeません。

于 2010-10-05T14:47:39.963 に答える
1

これは、プログラマーが犯す可能性のある何千もの「ほとんどエラー」の 1 つにすぎません。MS はそれらのほとんどをキャッチしました。

彼らはこれを逃しました。

なぜ「私」が変わらないかというと、それはとても良いことです! 「me」を使用すると、安全のために、作業している実際のクラスのコピーが渡されます。これがあなたが望んでいたように機能した場合、私たちは巨大な副作用について話しているでしょう. クラスのメソッドで無邪気に作業を進めていると、突然BAMが発生し、まったく別のオブジェクトに移動します。それはひどいでしょう!それを行う場合は、すべてのグローバルがランダムに設定され、サブ/関数が含まれていないスパゲッティ MS-Basic の行番号付きコードを作成することもできます。

これが機能する方法は、括弧で引数を渡す場合と同じです。たとえば、これは期待どおりに機能します。

Assign(Reference_I_Want_To_Set, New Assigner)

しかし、これは何も変更しません:

Assign((Reference_I_Want_To_Set), New Assigner)

上記のタイプのコードを adam101 が示唆するように反映すると、同様の結果が表示されます。Meこれは括弧に対する大きなフラストレーションですが、 !!!については非常に良いことです。

于 2010-10-05T13:36:36.883 に答える
0

このコードを機能させるために必要なことは次のとおりです。

Class Assigner
''// Ignore this for now.

Private newPropertyValue As Integer
Public Property NewProperty() As Integer
    Get
        Return newPropertyValue
    End Get
    Set(ByVal value As Integer)
        newPropertyValue = value
    End Set
End Property


''// This part is not so weird... take another instance ByRef,
''// assign it to a different instance -- stupid but whatever. '
Shared Sub Assign(ByRef x As Assigner, ByVal y As Assigner)
    x = y
End Sub

''// But... what's this?!?
Shared Sub AssignNew(ByRef x As Assigner)
    ''// Passing "Me" ByRef???
    Assign(x, New Assigner)
End Sub
End Class

次に、次のように使用します

    Dim a As New Assigner With {.NewProperty = 10}

    Assigner.AssignNew(a)

私の理解では、使用中にオブジェクトの参照を変更できないため、共有サブで変更する必要があります


Meは割り当てのターゲットになることはできないため、コードはそのコピーを作成するように見え、その時点から、実際のオブジェクトを使用するのではなく、そのコピーを使用します

于 2010-10-05T13:14:09.357 に答える