为什么调用空操作会抛出NullReferenceException异常?

6
为什么我必须检查一个Action对象是否为null以避免出现NullReferenceException异常?如果没有这个操作,那么直接不做任何操作并继续进行不是很合理吗?我不明白为什么会抛出异常。Action是一个类,为什么它自己不能处理这个问题?

这就是规则,它们保证了你的安全。为什么不把所有错误都忽略掉呢?那样所有程序都会“运行”! - spender
1
我有点困惑,你改变了被接受的答案,尽管现在被接受的并没有回答你所提出的实际问题,即为什么会出现异常。 - Jon Skeet
Jon,加油,你是网站上最聪明的人之一 :) 我实际的潜在问题是找到一种在未设置时调用该操作而不会产生异常的方法。C# 6.0中的?.完美地运行,并且更加简洁。这就是为什么它是我个人首选的答案,其他用户可以投票选择他们认为最好的答案。 - user1306322
1
我同意@JonSkeet的观点,特别是因为他是该网站上最聪明的人之一。你问了“为什么”,而被选中的答案并没有提供“为什么”的解释,而Jon的回答则同时提供了你所寻找的“为什么”和“如何”。 - Michel Feinstein
@mFeinstein 乔恩可能很聪明,但我问的原因与此无关 :p - user1306322
1
你在问题中从未提到你的原因,尽管我们都很聪明,但我们仍然不是心灵读者... 是的,我们可以猜测你背后的原因,但你知道那句话“当你假设时,你让你和我都成了傻瓜”... 我认为答案必须与问题相匹配,如果你正在寻找其他东西,你应该相应地提问... 但这只是我的个人意见。 - Michel Feinstein
3个回答

18
您正在尝试在对象上调用实例方法(Invoke)。如果使用null引用,则这样做始终会导致NullReferenceException错误1。例如:

 object x = null;
 string y = x.ToString();

你觉得object.ToString()也应该处理这个吗?

基本上,这与类型系统的其余部分保持一致。 C#语言 可能以不同的方式设计 - 可能仅针对action()的“速记”表示为action.Invoke() - 但它没有,并且现在不会改变。

如果想要的话,向Action添加自己的扩展方法也很容易:

public static class ActionExtensions
{
    public static void NullSafeInvoke(this Action action)
    {
        if (action != null)
        {
            action();
        }
    }
}

或者使用C# 6的空值条件运算符,只有在引用非空时才调用委托:
myAction?.Invoke();

(这适用于任何委托类型,不仅仅是动作 - 对于EventHandler,您可以使用类似于handler?.Invoke(this,new EventArgs())的内容。如果handler为空,则甚至不会调用EventArgs()构造函数。)

1 至少需要使用C#。 在IL中,有一些在null引用上非虚拟地调用实例方法的方法,但这远非正常情况。


我想我会使用这个扩展。 - user1306322
在VB中,我得到了“'NullSafeInvoke'不是'System.Action'的成员”的错误。除此之外,我其他几十个扩展方法都能正常工作,没有任何问题。我们需要做一些特殊的事情来连接一个Action扩展方法吗? - InteXX
没关系,那只是一个编译/引用问题。谢谢!+1 - InteXX

17

自从C# 6.0版本,你可以:

myAction?.Invoke();

不需要扩展方法。


这个能在C# 4.0上使用吗? - OscarLeif
2
你是在询问 C# 语言版本还是 .NET Framework 版本?只是想确认一下,因为它们有不同的版本。 - Eiver
这是针对Unity游戏引擎的,它们使用的是.Net Framework 3.5版本。 - OscarLeif
空值条件运算符不依赖于框架版本本身,而是依赖于编译器,必须支持该特性。如果您使用的是Visual Studio 2015或更高版本,则仍然可以针对.NET 3.5并同时使用该运算符。 - Eiver

8

Action是一个委托(delegate),而不是一个类。当你调用一个action时,如下所示:

myAction();

这里真正发生的是这样的:
myAction.Invoke();

如果myActionnull,则在null实例上调用Invoke,这自然会引发NullReferenceException

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接