跨越这行代码:
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
这两个问号意味着什么,是某种三元运算符?谷歌很难找到.
它是空合并运算符,非常类似于三元(立即if)运算符.另见?? 运营商 - MSDN.
FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
扩展为:
FormsAuth = formsAuth != null ? formsAuth : new FormsAuthenticationWrapper();
进一步扩展到:
if(formsAuth != null) FormsAuth = formsAuth; else FormsAuth = new FormsAuthenticationWrapper();
在英语中,它表示"如果左边的任何内容不为空,请使用它,否则使用右边的内容."
请注意,您可以按顺序使用任意数量的这些.下面的语句将指定第一个非空Answer#
来Answer
(如果所有答案都为空,则Answer
是空):
string Answer = Answer1 ?? Answer2 ?? Answer3 ?? Answer4;
值得一提的是,虽然上面的扩展在概念上是等价的,但每个表达式的结果只评估一次.例如,如果表达式是带副作用的方法调用,则这很重要.(感谢@Joey指出这一点.)
仅仅因为没有其他人说过神奇的话:它是空的合并运算符.它在C#3.0语言规范的第7.12节中定义.
它非常方便,特别是因为它在表达式中多次使用时的工作方式.表格形式:
a ?? b ?? c ?? d
a
如果它是非null,则会给出表达式的结果,否则尝试b
,否则尝试c
,否则尝试d
.它在每个点都短路.
此外,如果类型d
是非可空的,则整个表达式的类型也是不可为空的.
它是空合并运算符.
http://msdn.microsoft.com/en-us/library/ms173224.aspx
是的,几乎不可能搜索,除非你知道它叫什么!:-)
编辑:这是另一个问题的一个很酷的功能.你可以链接它们.
C#的隐藏功能?
谢谢大家,这是我在MSDN网站上找到的最简洁的解释:
// y = x, unless x is null, in which case y = -1. int y = x ?? -1;
??
当值为null时,是否为可空类型提供值.因此,如果formsAuth为null,它将返回新的FormsAuthenticationWrapper().
两个问号(??)表示它是一个Coalescing运算符.
Coalescing运算符返回链中的第一个NON-NULL值.你可以看到这个youtube视频,它实际上展示了整个事物.
但是,让我为视频所说的内容添加更多内容.
如果你看到合并的英文含义,就说"合并在一起".例如,下面是一个简单的合并代码,它链接了四个字符串.
所以,如果str1
是null
,它会尝试str2
,如果str2
是null
,它会尝试str3
依此类推,直到它找到一个非空值的字符串.
string final = str1 ?? str2 ?? str3 ?? str4;
简单来说,Coalescing运算符从链中返回第一个NON-NULL值.
这是三元运营商的捷径.
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";
合并运算符
它相当于
FormsAuth = formsAUth == null ? new FormsAuthenticationWrapper() : formsAuth
这没什么危险的.事实上,它是美丽的.如果需要,您可以添加默认值,例如:
码
int x = x1 ?? x2 ?? x3 ?? x4 ?? 0;
正如许多答案中正确指出的那样是"空合并运算符"(??),说到你也可能想要查看它的表兄"Null-conditional Operator"(?.或?[),它是一个运算符很多次它与??一起使用
空条件运算符
用于在执行成员访问(?.)或索引(?[)操作之前测试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;
这更冗长,更麻烦.
只为了你的娱乐(知道你们都是C#伙伴;-).
我认为它起源于Smalltalk,它已存在多年.它定义为:
在对象中:
? anArgument ^ self
在UndefinedObject(又名nil的类)中:
? anArgument ^ anArgument
这有评估(?)和非评估版本(??).
在getter-methods中经常可以找到惰性初始化的私有(实例)变量,这些变量在真正需要之前保持为零.
这里使用合并获取值的一些示例是低效的.
你真正想要的是:
return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();
要么
return _formsAuthWrapper ?? (_formsAuthWrapper = new FormsAuthenticationWrapper());
这可以防止每次都重新创建对象.而不是私有变量保持为null并且在每个请求上创建新对象,这确保在创建新对象时分配私有变量.
我已经阅读了整个这个主题以及其他许多内容,但我找不到这样的全面答案.
通过它我完全理解"为什么要使用??以及何时使用??以及如何使用??".
资源: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.NullablemyNullableInteger = null; myNullableInteger = 1; if (myNullableInteger != null) { Console.WriteLine(myNullableInteger.Value); }
C#编程语言提供了一种缩写语法,用于声明从System.Nullable构造的类型.该语法允许缩写:
System.NullablemyNullableInteger;
至
int? myNullableInteger;
编译器将阻止尝试以这种方式将可空值类型的值分配给普通值类型:
int? myNullableInteger = null; int myInteger = myNullableInteger;
它可以防止这样做,因为可以为null的值类型可以具有null值,在这种情况下它实际上具有该值,并且该值不能分配给普通值类型.虽然编译器会允许这段代码,
int? myNullableInteger = null; int myInteger = myNullableInteger.Value;
第二个语句将导致抛出异常,因为如果从System.Nullable构造的类型没有被赋予有效的T值,那么任何访问System.Nullable.Value属性的尝试都是无效的操作,这在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.