两个问号 - c#问号点




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

注意:

我已经阅读了整个这个主题和其他许多内容,但是我无法找到像这样彻底的答案。

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

资源:

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

可为空的值类型

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

.NET Framework 2.0包含一个泛型类型定义,它提供了类似这样的情况,在这种情况下,人们希望将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,实际上在这种情况下会具有值,并且该值不能分配给普通的值类型。 虽然编译器会允许这些代码,

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

第二个语句会导致引发异常,因为如果从System.Nullable构造的类型尚未分配有效值T(在此未发生),则任何访问System.Nullable.Value属性的尝试都是无效操作案件。

结论:

将可空值类型的值分配给普通值类型的一种正确方法是使用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。

穿过这行代码:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

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


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


合并运营商

这相当于

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

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


它是空合并运算符,与三元运算符(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为空):

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

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


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

空条件运算符

用于在执行成员访问( ?。 )或索引( ?[ )操作之前测试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; 

这是更详细和繁琐。


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

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

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

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

这里使用合并获取值的一些示例效率不高。

你真正想要的是:

return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();

要么

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

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


FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

相当于

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

但关于它的一件很酷的事情是你可以像他人说的那样把它们连起来。 没有涉及的一个细节是,你可以使用它来抛出异常。

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




null-coalescing-operator