在C# 8.0中,调用方法前加感叹号的含义是什么?

152

我发现了一段看起来是用C#编写的8.0版本代码。在这段代码中,方法调用前有一个感叹号。请问这段代码的含义是什么,最重要的是它有什么用途?

var foo = Entity!.DoSomething();
3个回答

181
这就是null forgiving operator。它告诉编译器"这不是空的,相信我",因此它不会为可能的空引用发出警告。在这种特殊情况下,它告诉编译器Entity不是空的。

6
这只是为了消除警告吗?它不会影响性能,因为它是一种托管语言,所以编译器不能接受源代码的承诺,除非 能够证明它们始终为真。就代码生成而言,如果条件不成立,它将以令人兴奋的方式中断。我假设空指针引用通常只会捕获硬件 -> 操作系统异常,因此实际上并没有条件分支运行,这种情况下也不会有任何节省。 - Peter Cordes
3
@Peter-cordes:看起来你是正确的。从链接中可知:null-forgiving运算符在运行时没有任何影响。它只通过改变表达式的空值状态来影响编译器的静态流分析。在运行时,表达式x!会计算底层表达式x的结果。 - Ross Presser
3
你甚至可以写 null! 来表示对已序列化数据的完全信任,例如当进行反序列化时。如果你问我,这是非常具有讽刺意味的用法,一般情况下最好使用 [JsonConstructor] 属性,但我认为它展示了这个操作符的本质以及何时可能需要使用它。 - EriF89

45

!是空值适应运算符。具体而言,它有两个主要作用:

  • 将表达式的类型(在这种情况下是修改实体)从可空类型更改为非可空类型;(例如,object?变成object

  • 抑制与空值相关的警告,这可能会隐藏其他转换

这似乎特别与类型参数有关:

IEnumerable<object?>? maybeListOfMaybeItems = new object[] { 1, 2, 3 };

// inferred as IEnumerable<object?>
var listOfMaybeItems = maybeListOfMaybeItems!;

// no warning given, because ! supresses nullability warnings
IEnumerable<object> listOfItems = maybeListOfMaybeItems!;

// warning about the generic type change, since this line does not have !
IEnumerable<object> listOfItems2 = listOfMaybeItems;

38
这被称为空值容错运算符,它在C# 8.0及更高版本中可用。它只在编译时起作用,而不是在运行时。它的目的是告诉编译器某些可空类型的表达式不是 null,以避免可能的null引用警告。
在这种情况下,它告诉编译器Entity不是null。

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