为什么调用一个Action,即null,抛出NullReferenceException?

use*_*322 2 c# action nullreferenceexception

为什么我要检查一下Action是不是null要避免得到NullReferenceException?如果没有行动是不合逻辑的,那么可以随便什么也行不通?我不明白为什么它要抛出异常.Action是一个类,为什么不处理这个问题呢?

Jon*_*eet 13

您正在尝试Invoke在对象上调用实例方法().如果您使用引用1,那么总是会失败.例如:NullReferenceExceptionnull

 object x = null;
 string y = x.ToString();
Run Code Online (Sandbox Code Playgroud)

还应该object.ToString()处理吗?

基本上,这与其他类型系统的工作方式一致.C#语言可能是以不同的方式设计的 - 可能只是action()意义的"速记" action.Invoke()- 但事实并非如此,现在它不会改变.

Action如果您愿意,可以轻松添加自己的扩展方法:

public static class ActionExtensions
{
    public static void NullSafeInvoke(this Action action)
    {
        if (action != null)
        {
            action();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

或者使用C#6 空条件运算符仅在引用为非null时调用委托:

myAction?.Invoke();
Run Code Online (Sandbox Code Playgroud)

(这适用于任何委托类型,而不仅仅是动作 - EventHandler例如,你可以使用类似的东西handler?.Invoke(this, new EventArgs()).EventArgs()如果handler为null,甚至不会调用构造函数.)


1至少使用C#.有一些方法可以在IL中非虚拟地"引用"空引用上调用实例方法,但它远非正常.


Eiv*_*ver 10

从C#6.0开始,您可以:

myAction?.Invoke();
Run Code Online (Sandbox Code Playgroud)

无需扩展方法.

  • 您是要求 C# 语言版本还是 .NET Framework 版本?只是想确定一下,因为它们是单独进行版本控制的。 (2认同)

Dan*_*rth 7

Action是一个代表,而不是一个阶级.当你调用一个动作时,如下所示:

myAction();
Run Code Online (Sandbox Code Playgroud)

这里真正发生的是:

myAction.Invoke();
Run Code Online (Sandbox Code Playgroud)

如果myActionnull你调用Invoke一个null实例,这是自然引起了NullReferenceException.