提问



跨越这行代码:


FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();


这两个问号意味着什么,是某种三元运算符?
在谷歌看起来很难。

最佳参考


它是空的合并运算符,与三元(立即数)运算符非常相似。另请参见??运算符 - MSDN。[51]


FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();


扩展为:


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


进一步扩展到:


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


在英语中,它意味着如果左边的任何东西不是空的,那就用它,否则使用右边的东西。


请注意,您可以按顺序使用任意数量的这些。以下语句将第一个非null Answer#赋给Answer(如果所有Answers都为null,则Answer为null):


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





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

其它参考1


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


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


a ?? b ?? c ?? d


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


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

其它参考2


它是空的合并算子。


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


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


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


C#的隐藏特征?

其它参考3


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


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

其它参考4


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

其它参考5





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


Coalescing运算符返回链中的第一个NON-NULL值。你可以看到这个youtube视频,它实际上展示了整个事物。[55]


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


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


所以如果str1null,它会尝试str2,如果str2null,它会尝试str3,依此类推,直到找到一个字符串为止具有非空值。


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


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

其它参考6


这对于三元运营商来说是个昙花一现。


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


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


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

其它参考7


如果你熟悉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";

其它参考8


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


我认为它起源于Smalltalk,它已存在多年。它定义为:


在对象中:


? anArgument
    ^ self


在UndefinedObject(又名nil的类)中:


? anArgument
    ^ anArgument


这有评估(?)和非评估版本(??)。

在getter-methods中经常可以找到惰性初始化的私有(实例)变量,它们在真正需要之前保持为零。

其它参考9


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


CODE


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

其它参考10


合并运算符


它相当于


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

其它参考11


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


你真正想要的是:


return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();


要么


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


这可以防止每次都重新创建对象。而不是私有变量保持为null并且在每个请求上创建新对象,这确保在创建新对象时分配私有变量。

其它参考12


正如许多答案中正确指出的那样是空合并运算符( ?? ),说到你也可能想要查看它的表兄Null-conditional Operator(? 。?[[)这是一个多次与 ?? 一起使用的运算符


空条件运算符[56]



  用于在执行成员访问(?。)或索引(?[[)操作之前测试null。这些运算符可帮助您编写更少的代码来处理空值检查,尤其是降序到数据结构中。



例如:


// 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; 


这更冗长,更麻烦。

其它参考13


注意:的



我已经阅读了整个这个帖子以及其他许多内容,但我找不到这样的答案。


通过它我完全理解为什么要使用??以及何时使用??以及如何使用??。


来源:



Windows通信基础由Craig McMurtry释放
ISBN 0-672-32948-4


可空值类型



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


.NET Framework 2.0包含一个泛型类型定义,它提供了类似这样的情况,其中一个人想要将null分配给值类型的实例,并测试实例的值是否为null。该泛型类型定义是System.Nullable,它约束可以替换T到值类型的泛型类型参数。
从System.Nullable构造的类型实例可以赋值为null;实际上,默认情况下它们的值为空。因此,构造的类型
System.Nullable可以称为可空值类型。
System.Nullable有一个属性Value,通过该属性赋值给一个实例
如果实例的值不为null,则可以获得从中构造的类型。
因此,人们可以写:


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


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


System.Nullable<int> myNullableInteger;





int? myNullableInteger;


编译器将阻止尝试以这种方式将可空值类型的值分配给普通值类型:


int? myNullableInteger = null;
int myInteger = myNullableInteger;


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


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


第二个语句将导致抛出异常,因为任何尝试
如果是类型,则访问System.Nullable.Value属性是无效操作
从System.Nullable构造的尚未被赋予有效的T值,在这种情况下没有发生。


结论:



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


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


另一种选择是使用以下语法:


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


通过为普通整数myInteger分配可空整数myNullableInteger的值,如果后者已被赋予有效整数值;否则,myInteger的值为-1。

其它参考14


FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();


相当于


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


但关于它的一个很酷的事情是你可以链接它们,就像其他人说的那样。
没有触及的一个很薄的是你实际上可以使用它来抛出异常。


A = A ?? B ?? throw new Exception("A and B are both NULL");

其它参考15


它是一个空的合并运算符,与三元运算符的工作方式类似。


    a ?? b  => a !=null ? a : b 


另一个有趣的观点是,
可以为空的类型可以包含值,也可以是未定义的。
因此,如果您尝试将可空值类型分配给不可为空的值类型
您将收到编译时错误。


int? x = null; // x is nullable value type
int z = 0; // z is non-nullable value type
z = x; // compile error will be there.


所以要做到这一点?? ??运营商:


z = x ?? 1; // with ?? operator there are no issues