WithEvents
は、.NET Framework自体がネイティブにサポートしていない機能です。 VB.NETは.NET上で実装しています。この機能は、VB6でも提供されています。しかし、COMと.NET間のイベントモデルの根本的な違いのために、VB6で機能が実装された方法は非常に異なります。
VB6でどのように機能が実装されたかについては触れません。それは本当に関連性がありません。重要なのは、.NETでイベントがどのように機能するかです。基本的に、.NETでは、イベントは明示的にフックされ、アンフックされなければなりません。イベントが定義されると、プロパティの定義方法には多くの類似点があります。特に、プロパティに「set」メソッドと「get」メソッドの対称性と同様に、ハンドラをイベントに追加するメソッドと、ハンドラを削除するメソッドがあります。
イベントがこのようなメソッドを使用する理由は、外部の呼び出し元から接続されたハンドラのリストを非表示にするためです。クラス外のコードが、添付されたハンドラの完全なリストにアクセスできる場合、それが干渉する可能性があり、非常に混乱する可能性のあるプログラミング慣行が非常に貧弱です。
VB.NETは、AddHandler
とRemoveHandler
演算子を使用して、これらのイベントの「追加」および「削除」メソッドへの直接呼び出しを公開します。 C#では、正確に同じ基礎となる操作は、+=
と-=
演算子を使用して表現されます。ここで、左側の引数はイベントメンバー参照です。
WithEvents
は、AddHandler
とRemoveHandler
の呼び出しを隠す構文糖です。認識しておくべき重要なことは、のコールが依然としてであることです。これらは暗黙的です。だから、
、あなたがこのようなコードを記述します。
Private WithEvents _obj As ClassWithEvents
Private Sub _obj_GronkulatedEvent() Handles _obj.GronkulatedEvent
...
End Sub
..youは、VBを求めています。NETを_obj
(いつでもオブジェクト参照を変更することができます念頭に置いて)に割り当てられていることを確認するには、GronkulatedEvent
イベントはそのSub
で処理する必要があります。参照を変更する場合は、古いオブジェクトのGronkulatedEvent
をすぐに切り離し、新しいオブジェクトのGronkulatedEvent
を添付する必要があります。
VB.NETはフィールドをプロパティに変換することでこれを実装しています。 WithEvents
を追加すると、フィールド_obj
(または、場合によっては_item
)がであり、実際にはフィールドではありません。秘密裏フィールドを作成し、その後_item
されるが、実装がこのようになりますプロパティを次のようになります。
だから、
Private __item As ItemViewModel ' Notice this, the actual field, has two underscores
Private Property _item As ItemViewModel
<CompilerGenerated>
Get
Return __item
End Get
<CompilerGenerated, MethodImpl(Synchronized)>
Set(value As ItemViewModel)
Dim previousValue As ItemViewModel = __item
If previousValue IsNot Nothing Then
RemoveHandler previousValue.GronkulatedEvent, AddressOf _item_GronkulatedEvent
End If
__item = value
If value IsNot Nothing Then
AddHandler value.GronkulatedEvent, AddressOf _item_GronkulatedEvent
End If
End Set
End Property
、なぜこれはあなたが見る「ラグ」を引き起こしていますか?まあ、あなたは "ByRef"プロパティを渡すことはできません。何か "ByRef"を渡すには、そのメモリアドレスを知る必要がありますが、プロパティは "get"と "set"メソッドの背後にあるメモリアドレスを隠します。 C#のような言語では、コンパイル時エラーが発生します。プロパティはL値ではないため、参照は渡せません。しかし、VB.NETはより寛容で、あなたのために機能するように、舞台裏で余分なコードを書いています。あなたのコードで
、あなたはフィールドなので、それは、新しい値を書き込むことができ、パラメータByRef
を取るSetProperty
に_item
メンバー、どのように見えるか渡しています。しかし、WithEvents
のため、_item
メンバーは本当にプロパティです。だから、VB.NETは何をしますか? WithEvents
はプロパティに、あなたのフィールドを変換しているため、VB.NETは、実際のを延期しなければならなかった、だから、
Public Property Item As ItemViewModel
Get
Return _item ' This is actually a property returning another property -- two levels of properties wrapping the actual underlying field -- but VB.NET hides this from you
End Get
Set
' You wrote: SetProperty(_item, value)
' But the actual code emitted by the compiler is:
Dim temporaryLocal As ItemViewModel = _item ' Read from the property -- a call to its Get method
SetProperty(temporaryLocal, value) ' SetProperty gets the memory address of the local, so when it makes the assignment, it is actually writing to this local variable, not to the underlying property
_item = temporaryLocal ' Once SetProperty returns, this extra "glue" code passes the value back off to the property, calling its Set method
End Set
End Property
:それはSetProperty
への呼び出しのための一時的なローカル変数を作成し、呼び出し後のプロパティに戻ってそれを割り当てSetProperty
への呼び出しが返るまでプロパティへの代入。
希望は意味があります! :-)
ありがとうジョナサン! –
フォローアップ:IDisposableの使用を禁止的に困難にする従来の問題があります。私たちはIDisposableを実装することができず、残りのハンドルをクリーンアップするためにDispose()が呼び出されることに依存しているため、WithEventsを使用するとこれを回避して、クリーンアップを処理するという考えがありました。 ** 1)** WithEventsは、オブジェクトがもはや使用されていないときに実際にハンドルを解放するので、正しくガベージコレクションされますか? ** 2)**オブジェクトが不要になったときにハンドルをリークすることなくAddHandlerとRemoveHandlerを使用できるようにするIDisposableの代替手段はありますか? –
ええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええええ>>おかあさんは、実際に廃棄する必要があるオブジェクトが処分されることを確実にする方法は1つだけあり、それは 'Dispose'メソッドを呼び出すことです。コードの特定のスコープでオブジェクトを使用している場合、これを 'Using'ステートメントで自動的に行うことができます。 –