在 C# 8.0 中调用方法之前感叹号是什么意思?

icn*_*icn 58 c# null nullable c#-8.0

我发现了一段用 C# 编写的代码,貌似是 8.0 版。在代码中,在调用方法之前有一个感叹号。这部分代码是什么意思,最重要的是,它的用途是什么?

var foo = Entity!.DoSomething();
Run Code Online (Sandbox Code Playgroud)

M. *_*osi 54

这将是空原谅运算符
它告诉编译器“这不是空的,相信我”,所以它不会对可能的空引用发出警告。

在这种特殊情况下,它告诉编译器Entity不为空。

  • 所以这只是为了消除警告?它不会影响性能,不是吗?因为它是一种托管语言,所以编译器不能接受源代码承诺,除非*它*可以证明它们总是正确的,就代码生成而言,它会以令人兴奋的方式破坏如果条件为假。(我假设 null-deref 通常只是捕获硬件 -> 操作系统异常,因此它实际上不会每次都进行条件分支,并且在这种情况下不会有任何保存。) (3认同)
  • @Peter-cordes:看起来你是对的。从链接:`null-forgiving 运算符在运行时不起作用。它仅通过更改表达式的空状态来影响编译器的静态流分析。在运行时,表达式 x! 计算出基础表达式 x 的结果。` (3认同)
  • 您甚至可能会发现编写“null!”很有用,例如在完全确信该属性将位于序列化数据中进行反序列化时。如果您问我,这是非常讽刺的用例,一般来说,使用 [JsonConstructor] 属性可能更好,但我认为它说明了此运算符的性质以及您何时可能想要使用它。 (2认同)

Jav*_*tíz 17

这称为null-forgiving 运算符,在 C# 8.0 及更高版本中可用。它在运行时不起作用,只在编译时起作用。其目的是通知编译器可空类型的某些表达式不为空,以避免可能出现有关空引用的警告。

在这种情况下,它告诉编译器Entity不为空。


Dav*_*eau 16

!是 Null-Forgiving 运算符。具体来说,它有两个主要作用:

  • 它将表达式的类型(在这种情况下是修改Entity)从可空类型更改为不可为空类型;(例如,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;
Run Code Online (Sandbox Code Playgroud)