繁体   English   中英

自测委托:避免在调用前检查null?

[英]Self-Testing delegates: avoid checking for null before invocation?

有什么聪明的方法可以避免在以常规方式调用事件之前测试事件的无效性的冗长性? 看起来很明显,如果我呼叫一个代表,我希望它被分配。
(如果我真的想/需要测试其无效性,我最终可以明确地进行,但是系统地进行此测试是一种乏味而冗长的操作。)

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();
}
public event EventHandler NoDataEventHandler = delegate{};

以这种方式声明一个事件意味着它永远不会为空。 至少将始终挂接一个无操作事件处理程序。

就您而言

public event ResetTradesDelegate ResetTradesEvents = delegate{};

触发事件总是要具有与之相关的竞赛条件。 您可能会冒险尝试在null时调用委托,或者在事件取消钩挂后调用委托。 埃里克·利珀特(Eric Lippert)在这里就该主题写了一篇相当全面的文章。 上面的技术仍然遭受第二种竞争条件的困扰,因此在取消钩住事件之后,事件处理程序需要健壮才能被调用。

static void CallIfNotNull(this Action action)
{
 if (action != null) action();
}

作为扩展方法,使用起来非常方便。

您可以使用始终订阅的无操作事件来创建事件处理程序:

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

    public event EventHandler Event;

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

但是,这需要订阅您的事件,并且由于无操作委托仍将存在于已订阅事件处理程序列表中,因此会导致性能下降。


我的首选是创建一对扩展方法来调用任何事件处理程序,同时执行空安全检查:

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#语言这一臭味部分的一种很好的可重用方法。

public static void Call(this Action action)
{
    var safeAction = Interlocked.CompareExchange(ref action, null, null);
    if (safeAction != null)
        safeAction();
}

使用空条件运算符可以保留测试,但比较冗长,因此对我有用。 我不认为它可以解决其他人提到的比赛条件。

ResetTradesEvent?.Invoke();

在Visual Studio 2017中会自动建议这样做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM