在C#中,两个问号在一起意味着什么?

穿过这行代码:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 

这两个问号是什么意思,它是一种三元运算符? 在Google中查找是很困难的。

它是空合并运算符,和三元运算符(immediate-if)非常相似。 另见? 运营商 – MSDN 。

 FormsAuth = formsAuth ?? new FormsAuthenticationWrapper(); 

扩展到:

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

进一步扩展到:

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

在英文中,它的意思是“如果左边的东西不是空的,那就用,否则用右边的东西”。

请注意,您可以按顺序使用其中的任意数量。 下面的语句将把第一个非空的Answer#分配给Answer (如果所有Answers都是null,那么Answer就是null):

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

另外值得一提的是,上面的扩展在概念上是等价的,每个expression式的结果只被评估一次。 例如,一个expression式是带有副作用的方法调用,这非常重要。 (感谢@Joey指出了这一点。)

就因为没有其他人说过这些神奇的话:它是无效的合并算子 。 它在C#3.0语言规范的 7.12节中定义。

这非常方便,特别是因为它在expression式中多次使用时的工作方式。 一个expression式的forms:

 a ?? b ?? c ?? d 

会给出expression式的结果,如果它是非空的,否则尝试b ,否则尝试c ,否则尝试d 。 它在每个点都短路。

另外,如果d的types是不可空的,则整个expression式的types也是不可空的。

这是空合并运算符。

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

是的,几乎不可能search,除非你知道它叫什么! 🙂

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

C#隐藏的function?

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

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

?? 有没有为值为null时为可空types提供一个值。 所以,如果formsAuth为null,它将返回新的FormsAuthenticationWrapper()。

在这里输入图像描述

两个问号(??)表示它是一个合并操作符。

合并运算符返回链中的第一个非空值。 你可以看到这个YouTubevideo,实际上演示了整个事情http://www.youtube.com/watch?v=YJGGmTNHPeo

但让我补充一下video所说的内容。

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

因此,如果“str1”为空,它将尝试“str2”,如果“str2”为空,它将尝试“str3”等,直到find一个非空值的string。

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

简而言之,合并操作符返回链中的第一个非空值。

这对于三元操作员来说是短暂的。

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

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

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

如果你熟悉Ruby,那么||=看起来就像C#一样。 对我来说。 这里有一些Ruby:

 irb(main):001:0> str1 = nil => nil irb(main):002:0> str1 ||= "new value" => "new value" irb(main):003:0> str2 = "old value" => "old value" irb(main):004:0> str2 ||= "another new value" => "old value" irb(main):005:0> str1 => "new value" irb(main):006:0> str2 => "old value" 

而在C#中:

 string str1 = null; str1 = str1 ?? "new value"; string str2 = "old value"; str2 = str2 ?? "another new value"; 

只为了你的娱乐(知道你们都是C#的人;-)。

我认为它起源于已经存在了很多年的Smalltalk。 它被定义为:

在对象中:

 ? anArgument ^ self 

在UndefinedObject(aka的类)中:

 ? anArgument ^ anArgument 

有评估(?)和非评估版本(??)。
它经常在lazy-initialized私有(实例)variables的getter方法中find,这些variables在真正需要的时候保留为零。

没有什么危险的。 事实上,它是美丽的。 如果需要,您可以添加默认值,例如:

 int x = x1 ?? x2 ?? x3 ?? x4 ?? 0; 

合并运营商

这相当于

 FormsAuth = formsAUth == null ? new FormsAuthenticationWrapper() : formsAuth 

这里使用合并获取值的一些例子是低效的。

你真正想要的是:

 return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper(); 

要么

 return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper()); 

这可以防止对象每次都被重新创build。 取而代之的是私有variables保持为空,并在每个请求上创build一个新对象,这确保了在创build新对象时分配私有variables。

正确地指出了许多答案,即“空合并运算符”( ?? ),你可能还想看看它的表亲“空条件运算符”( ?。?[ )是一个运算符很多时候,它是与

空条件运算符

用于在执行成员访问( ?。 )或索引( ?[ )操作之前testingnull。 这些运算符可以帮助您编写更less的代码来处理空检查,特别是降序到数据结构。

例如:

 // if 'customers' or 'Order' property or 'Price' property is null, // dollarAmount will be 0 // otherwise dollarAmount will be equal to 'customers.Order.Price' int dollarAmount = customers?.Order?.Price ?? 0; 

旧的方式没有 这样做的

 int dollarAmount = customers != null && customers.Order!=null && customers.Order.Price!=null ? customers.Order.Price : 0; 

这是比较冗长和繁琐的。

注意:

我已经阅读了整个这个线程和许多其他人,但我不能find这样的彻底的答案。

我完全理解了“为什么要使用?何时使用??以及如何使用?”。

资源:

Windows通信基础释放由Craig McMurtry国际标准书号0-672-32948-4

可空值types

有两种常见的情况,人们想知道一个值是否被赋值给一个值types的实例。 第一种情况是实例在数据库中表示一个值。 在这种情况下,人们希望能够检查实例以确定数据库中是否确实存在值。 另一种与本书主题更相关的情况是,实例表示从某个远程源接收的数据项。 再次,人们希望从实例中确定是否接收到该数据项的值。

.NET Framework 2.0包含了一个genericstypes定义,它提供了这样的情况,在这种情况下,人们希望将null分配给值types的实例,并testing实例的值是否为null。 该genericstypes定义是System.Nullable,它约束了genericstypes参数,可以用T代替值types。 从System.Nullable构造的types的实例可以赋值为null; 实际上,它们的值默认为空。 因此,从System.Nullable构造的types可能被称为可为空的值types。 System.Nullable具有一个属性Value,如果实例的值不为null,则可以通过该属性获取分配给由其构造的types实例的值。 所以可以这样写:

 System.Nullable<int> myNullableInteger = null; myNullableInteger = 1; if (myNullableInteger != null) { Console.WriteLine(myNullableInteger.Value); } 

C#编程语言为声明从System.Nullable构造的types提供了缩写语法。 该语法允许缩写:

 System.Nullable<int> myNullableInteger; 

 int? myNullableInteger; 

编译器将防止试图通过这种方式将可空值types的值分配给普通的值types:

 int? myNullableInteger = null; int myInteger = myNullableInteger; 

它可以防止这样做,因为可空值types可能具有值null,实际上在这种情况下会具有值,并且该值不能被分配给普通的值types。 虽然编译器会允许这个代码,

 int? myNullableInteger = null; int myInteger = myNullableInteger.Value; 

第二个语句会导致exception被抛出,因为任何尝试访问System.Nullable.Value属性是一个无效的操作,如果从System.Nullable构造的types没有被赋予一个有效的T值,这在这没有发生案件。

结论:

将可空值types的值分配给普通值types的一种正确方法是使用System.Nullable.HasValue属性来确定T的有效值是否已分配给可为null的值types:

 int? myNullableInteger = null; if (myNullableInteger.HasValue) { int myInteger = myNullableInteger.Value; } 

另一个select是使用这个语法:

 int? myNullableInteger = null; int myInteger = myNullableInteger ?? -1; 

如果后者被分配了一个有效的整数值,那么通过这个常量整数myInteger被分配可以为空的整数“myNullableInteger”的值; 否则,myInteger被赋值为-1。