9

一般的な方法でイベントを呼び出す前に、イベントの nullity をテストする冗長性を回避するスマートな方法はありますか? デリゲートを呼び出す場合、それを割り当てたいのは明らかです。
(その無効性を本当にテストしたい/テストする必要がある場合は、最終的には明示的に行うことができますが、このテストを体系的に行うのは面倒で冗長です。)

public delegate void ResetTradesDelegate();
public ResetTradesDelegate ResetTradesEvents;

public void OnSessionRxAdmMessage(IVfxFixAppSession session, FixMessage msg)
{    
    if (ResetTradesEvent != null)  //<-- Is there "any" a way not to write this test explicitly for each delegate ?
       ResetTradesEvent();
}
4

5 に答える 5

15
public event EventHandler NoDataEventHandler = delegate{};

この方法でイベントを宣言すると、null になることはありません。少なくとも、常に単一の no-op イベント ハンドラがフックされます。

あなたの場合、おそらく

public event ResetTradesDelegate ResetTradesEvents = delegate{};

イベントを発生させると、常に競合状態が関連付けられます。デリゲートが null のときにデリゲートを呼び出そうとするか、イベントのフックが解除された後にデリゲートを呼び出すリスクがあります。Eric Lippert は、このトピックに関するかなり包括的な投稿をここに書いています。上記の手法でも 2 番目のタイプの競合状態が発生するため、イベント ハンドラーは、イベントがフック解除された後に呼び出されることに対して堅牢である必要があります。

于 2012-07-12T20:30:11.823 に答える
4
static void CallIfNotNull(this Action action)
{
 if (action != null) action();
}

拡張メソッドとして、これは非常に便利に使用できます。

于 2012-07-12T20:39:32.117 に答える
2

常にサブスクライブされる no-op イベントを使用してイベント ハンドラーを作成できます。

public class MyClass
{
    public MyClass()
    {
        this.Event += (sender, e) => ();
    }

    public event EventHandler Event;

    protected virtual void OnEvent()
    {
        this.Event(this, EventArgs.Empty);
    }
}

ただし、これにはイベントをサブスクライブする必要があり、サブスクライブされたイベント ハンドラーのリストに no-op デリゲートがまだ存在するため、パフォーマンスが低下します。


ここでの私の好みは、null セーフ チェックを実行しながら、任意のイベント ハンドラーを呼び出す拡張メソッドのペアを作成することです。

public static void Raise(this EventHandler @event, object sender)
{
    if(@event != null)
    {
        @event.Invoke(sender, EventArgs.Empty);
    }
}

public static void Raise<TEventArgs>(
    this EventHandler<TEventArgs> @event,
    object sender,
    TEventArgs args)
    where TEventArgs : EventArgs
{
    if(@event != null)
    {
        @event.Invoke(sender, args);
    }
}

これは、ライブラリ内の任意の場所で簡単に呼び出して、イベントを安全に発生させることができます。

this.ResetTradesEvent.Raise(this);

これは純粋に構文糖衣です。あなたはまだデリゲートのチェックを行っています。ただし、C# 言語のこの臭い部分をまとめるには、再利用可能な優れた方法です。

于 2012-07-12T21:03:12.423 に答える
0
public static void Call(this Action action)
{
    var safeAction = Interlocked.CompareExchange(ref action, null, null);
    if (safeAction != null)
        safeAction();
}
于 2019-06-07T09:53:00.313 に答える