检查委托是否为null

Joa*_*nge 11 .net c# delegates

我正在阅读Essential C#3.0书籍,我想知道这是否是检查代表为空的好方法?:

class Thermostat
{
    public delegate void TemperatureChangeHandler ( float newTemperature );

    public TemperatureChangeHandler OnTemperatureChange { get; set; }

    float currentTemperature;

    public float CurrentTemperature
    {
        get { return this.currentTemperature; }
        set
        {
            if ( currentTemperature != value )
            {
                currentTemperature = value;

                TemperatureChangeHandler handler = OnTemperatureChange;

                if ( handler != null )
                {
                    handler ( value );
                }
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果类型是不可变的,解决方案是否会更改?我认为可能具有不变性,你不会遇到这个线程问题.

Joh*_*don 12

原始(有些不准确)回复:

关于这一点已经有很多讨论.

简而言之:即使执行此复制/检查null/execute步骤,也无法保证处理程序有效.

问题是,如果OnTemperatureChange在您复制它的时间和执行复制的时间之间取消注册,那么您可能无论如何都不希望执行侦听器.

您也可以这样做:

if (OnTemperatureChange != null )
{
    OnTemperatureChange ( value );
}
Run Code Online (Sandbox Code Playgroud)

并处理空引用异常.

我有时会添加一个不执行任何操作的默认处理程序,只是为了防止空引用异常,但这会非常严重地增加性能影响,尤其是在没有注册其他处理程序的情况下.

更新2014-07-10:

我推荐Eric Lippert.

我的原始回复确实提到了使用默认处理程序,但我不建议使用临时变量,我现在也认为这是一个很好的做法,根据文章.

  • 您可以保证,如果您手动编写事件的添加/删除代码并处理同步,否则多线程代码应处理可能的异常 (4认同)
  • Yerp,多线程代码在这方面是非常棘手的,请参阅:http://stackoverflow.com/questions/786383/c-events-and-thread-safety (3认同)
  • 事件处理程序即使在未注册后也应该优雅地处理被调用.只要委托持有对它的引用,事件处理程序所在的对象也不会被垃圾回收.简而言之,在创建事件委托的不可变副本并将其检查为null之后,执行副本是完全安全的.由此产生的任何错误都是处理程序的错误,必须予以纠正. (2认同)

Luc*_*ler 9

使用问号进行条件访问:

OnTemperatureChange?.Invoke();

  • @MatheusRocha Unity 使用 C# 7 已有一年多了。这 ?非 Unity 对象支持运算符 - 因此在委托的情况下,应该完全支持。 (3认同)
  • 仅适用于 C# 6 或更高版本。 (2认同)
  • C# 6 于 2016 年发布,您可以简单升级。 (2认同)
  • 我知道,这只是一个警告。并非所有环境都支持它。(例如,Unity 就不会) (2认同)

Mat*_*hen 5

在C. Ross的版本中推荐使用您给出的代码是有原因的。但是,约翰说的对,如果同时注销一个事件,还会有另一个问题。我链接的博客建议处理程序确保即使在未注册后也可以调用它们。