题 C#中两个问号共同意味着什么?


跨越这行代码:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

这两个问号意味着什么,是某种三元运算符? 在Google中查找起来很困难。


1322
2018-01-15 14:03


起源


这绝对是 不 三元运算符 - 它只有两个操作数!它有点像条件运算符(其中 是 三元)但空合并运算符是二元运算符。 - Jon Skeet
我在一次采访中解释说,未来的雇主之前曾对我的C#能力表示怀疑,因为我之前已经专业地使用过Java。他们之前没有听说过,并且在那之后没有质疑我对C#的熟悉程度:) - Jon Skeet
@Jon Skeet自从那个拒绝甲壳虫乐队的人以来,没有一个史诗般的失败能够识别技能。 :-)从现在开始,只需向他们发送一本书的副本,并在内封面上写下你的SO资料。 - Iain Holder
IainMH:对于它的价值,我没有 相当 开始写这本书了。 (或者也许我只是在制作第1章 - 类似的东西。)不可否认,搜索我会很快找到我的博客+文章等。 - Jon Skeet
Re:q中的最后一句 - 对于将来的ref,SymbolHound很适合这种事情,例如: symbolhound.com/?q=%3F%3F&l=&e=&n=&u= [对任何可疑的人 - 我没有任何关联,就像我找到一个好工具一样......] - Steve Chambers


答案:


它是空合并运算符,非常像三元(立即if)运算符。也可以看看 ??运营商 - MSDN

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

扩展为:

FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();

进一步扩展到:

if(formsAuth != null)
    FormsAuth = formsAuth;
else
    FormsAuth = new FormsAuthenticationWrapper();

在英语中,它表示“如果左边的任何内容不为空,请使用它,否则使用右边的内容。”

请注意,您可以按顺序使用任意数量的这些。以下语句将指定第一个非null Answer# 至 Answer (如果所有答案都是null,那么 Answer 一片空白):

string Answer = Answer1 ?? Answer2 ?? Answer3 ?? Answer4;

值得一提的是,虽然上面的扩展在概念上是等价的,但每个表达式的结果只评估一次。例如,如果表达式是带副作用的方法调用,则这很重要。 (感谢@Joey指出这一点。)


1807
2018-01-15 14:04



我不知道可以将这些链接起来 - Seiti
将这些链接起来可能具有潜在的危险性 - Coops
@CodeBlend,这并不危险。如果你要扩展,你只需要一系列嵌套的if / else语句。语法很奇怪,因为你不习惯看到它。 - joelmdev
如果它也适用于空字符串,它本来就是一个上帝发送:) - Zyphrax
@Gusdor ?? 是关联的,所以 a ?? b ?? c ?? d 相当于 ((a ?? b) ?? c ) ?? d。 “赋值运算符和三元运算符(?:)是右关联的。所有其他二元运算符都是左关联的。”资源: msdn.microsoft.com/en-us/library/ms173145.aspx - Mark E. Haase


只是因为没有其他人说过神奇的话:就是这样 null合并运算符。它在第7.12节中定义 C#3.0语言规范

它非常方便,特别是因为它在表达式中多次使用时的工作方式。形式的表达式:

a ?? b ?? c ?? d

将给出表达的结果 a 如果它是非null,否则尝试 b,否则试试 c,否则试试 d。它在每个点都短路。

另外,如果是这种类型的 d 是不可为空的,整个表达式的类型也是不可为空的。


232
2018-01-15 14:07



我喜欢你将它的含义简化为“null coalescing operator”。这就是我所需要的一切。 - FrankO
切向但相关:它现在在Swift中,但它是非常不同的:“Nil Coalescing Operator” developer.apple.com/library/ios/documentation/Swift/Conceptual/... - Dan Rosenstark


它是空合并运算符。

http://msdn.microsoft.com/en-us/library/ms173224.aspx

是的,几乎不可能搜索,除非你知道它叫什么! :-)

编辑:这是另一个问题的一个很酷的功能。你可以链接它们。

C#的隐藏功能?


64
2018-01-15 14:05



至少现在,它很容易搜索,即使你不知道名字,我只是用Google搜索 “双问号c#” - stivlo


谢谢大家,这是我在MSDN网站上找到的最简洁的解释:

// y = x, unless x is null, in which case y = -1.
int y = x ?? -1;

21
2018-01-15 14:09



这暗示了??的一个重要方面。运算符 - 它是为了帮助处理可空类型而引入的。在您的示例中,“x”的类型为“int?” (可空<int>的)。 - Drew Noakes
我认为代码片段应该是:int? y = x ?? -1; - vitule
@vitule no,如果空合并运算符的第二个操作数是不可为空的,那么结果是不可为空的(并且 -1 只是一个平原 int,这是不可空的)。 - Georges Dupéron
我真的希望它能像这样工作。我想一直这样做,但我不能,因为我使用的变量不是可以为空的类型。在coffeescript中工作y = x? -1 - PandaWood


?? 当值为null时,是否为可空类型提供值。因此,如果formsAuth为null,它将返回新的FormsAuthenticationWrapper()。


16
2018-01-15 14:05





enter image description here

两个问号(??)表示它是一个Coalescing运算符。

Coalescing运算符返回链中的第一个NON-NULL值。你可以看到 这个YouTube视频 这实际上证明了整个事情。

但是,让我为视频所说的内容添加更多内容。

如果你看到合并的英文含义,就说“合并在一起”。例如,下面是一个链接四个字符串的简单合并代码。

因此,如果 str1 是 null 它会尝试 str2如果 str2 是 null 它会尝试 str3 依此类推,直到找到一个非空值的字符串。

string final = str1 ?? str2 ?? str3 ?? str4;

简单来说,Coalescing运算符从链中返回第一个NON-NULL值。


14
2017-12-16 10:30



我喜欢这个解释,因为它有一个图表,然后最后一句用简单的术语解释它!它使人们很容易理解并增强我对使用的信心。谢谢! - Joshua K


这是三元运营商的捷径。

FormsAuth = (formsAuth != null) ? formsAuth : new FormsAuthenticationWrapper();

或者对于那些不做三元的人:

if (formsAuth != null)
{
  FormsAuth = formsAuth;
}
else
{
  FormsAuth = new FormsAuthenticationWrapper();
}

9
2018-01-15 14:05



我只纠正了“三元”的拼写,但实际上你的运算符是条件运算符。它碰巧是C#中唯一的三元运算符,但在某些时候它们可能会添加另一个运算符,此时“三元”将是模糊的,但“有条件的”不会。 - Jon Skeet
这是你可以做的简写 做 使用三元(条件)运算符。在你的长形式,两个测试(!= null)和第二个 formsAuth (之后 ?)可以改变;在null coalesce形式中,两者都隐式地获取您提供的值。 - Bob Sammers