は、私は上記のいくつかのコメントを残したが、私は、彼らが答えに出呼ばれるほど重要であると感じています。
まず、他の人が指摘したように、これは空の条件付き演算子です。
別のスレッドに変更した場合、イベントがチェックした後にヌルになる可能性があるため、このコードのバージョンは貧弱なスタイルと見なされます。
private void OnEvent(EventArgs e)
{
if (Event != null) Event(this, e);
}
は、しかし、私が呼び出すマルチスレッドプログラムは、上のイベントをサブスクライブし、退会ことに注意してください任意のスレッドは比較的まれです。
ヌル条件演算子の前に、標準的なアドバイスが追加されましたがclumsyを書くことだった:
private void OnEvent(EventArgs e)
{
var ev = Event;
if (ev != null) ev(this, e);
}
レースがある場合、これはnullの間接参照を排除します。
ヌル条件演算子は同じです。
private void OnEvent(EventArgs e)
{
Event?.Invoke(this, e);
}
これはvar ev = Event; if (ev != null) ev.Invoke(this, e);
のためだけの省略形です。
ローカルで、またはより簡潔には、?.
で、後者の2つのバージョンが「スレッドセーフ」であることを伝えます。 これらはではありません。これらはヌルを逆参照しませんが、それは面白いレースではありません。
Thread Alpha: create disposable object X -- say, a log file writer
Thread Alpha: subscribe X.H to event
Thread Bravo: Cause event to fire
Thread Bravo: Save X.H into local and check for null. It's not null.
Thread Alpha: Unsubscribe X.H from event
Thread Alpha: Call Dispose on X -- the log file is now closed.
Thread Bravo: Invoke X.H via the local
そして今、我々は、オブジェクトが正しく実装されている場合、例外「に配置されたオブジェクト」をスローする必要があり、破棄されたオブジェクト、上のメソッドを呼び出しています:面白いレースがあります。もしそうでなければ、ちょっと、クローズドファイルに書き込もうとすると、すべてが壊れてしまいます。マルチスレッド環境で
、イベントハンドラは、それらがイベントから退会されていても後、永遠にをを呼び出しても安全であることををを必要としています。コールサイトの「スレッドの安全性」はその問題を解決するものではありません。これはハンドラの要件です。しかし、ハンドブックの著者は、マルチスレッド環境で使用されることをどのようにして知っているのですか?しばしば、彼らはしません。だから事は壊れます。
好きではない場合は、は、複数のスレッドでイベントを使用するプログラムを作成しないでください。正しいことを得るのは本当に難しく、誰もが - ソースとハンドラの両方が協力して動作することを確認する必要があります。
ここで、ハンドラにロックを設定する解決策ではないと言う人もいますが、
private object HandleLocker = new object();
...
private void OnEvent(EventArgs e)
{
lock (HandleLocker)
{
if (Event != null)
Event(this, e);
}
}
そして同様にadd
とEvent
のremove
にロックを追加します。
これは病気よりも悪化する治療法です。
Thread Bravo takes out a lock on some object Foo and obtains it.
Thread Charlie wishes to fire the event.
Thread Charlie takes out a lock on HandleLocker and obtains it.
Thread Charlie calls the handler. The handler blocks trying to obtain Foo.
Thread Bravo attempts to subscribe a new handler, and blocks on HandleLocker.
ここでは、2つのスレッドのそれぞれがもう一方のスレッドを完了するのを待っています。 BravoはHandleLockerがCharlieによってリリースされるまで動かすことができず、CharlieはBravoによってFooがリリースされるまで動かすことができません。
これを絶対にしないでください。再度:マルチスレッドのイベント処理プログラムでは、が失効している間にハンドラが呼び出されることを保証する必要があります。ロックを使用してを実行することはできません。これは悪い状況です。ロックはスレッドを管理するための標準的なメカニズムです。
マルチスレッドは難しいです。事が間違っている可能性があるすべての方法とそれらを回避する方法を理解していない場合は、マルチスレッドプログラムを記述しないでください。
これは「null条件付き演算子」と呼ばれ、C#6.0の一部です。https://msdn.microsoft.com/en-us/library/dn986595.aspx –
これは[Null条件付き演算子](https ://msdn.microsoft.com/en-us/library/dn986595.aspx)。 – Igor
最初の例はスレッドセーフではないので、より良いことに注意してください。 ifの後、しかしあなたの呼び出しの前に、別のスレッドが 'Event'をnullに設定するとどうなりますか?あなたがそれを使いたくない場合、正しい構文は 'var localEvent = Event; if(localEvent!= null)localEvent(this、e); 'これはスレッドの安全性を保証するためです。 – dman2306