首页 文章

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

提问于
浏览
1380

跨越这行代码:

FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

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

16 回答

  • 19

    它是空合并运算符 .

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

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

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

    Hidden Features of C#?

  • 9

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

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

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

  • 66

    它是空合并运算符,非常类似于三元(立即if)运算符 . 另见?? Operator - MSDN .

    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指出这一点 . )

  • 0

    仅仅因为没有其他人说过神奇的话:它就是 null coalescing operator . 它在C# 3.0 language specification的第7.12节中定义 .

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

    a ?? b ?? c ?? d
    

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

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

  • 10

    enter image description here

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

    Coalescing运算符返回链中的第一个NON-NULL值 . 你可以看到this youtube video,它实际上展示了整个事物 .

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

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

    因此,如果 str1null ,它将尝试 str2 ,如果 str2null ,它将尝试 str3 ,依此类推,直到找到具有非空值的字符串 .

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

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

  • 11

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

    这是三元运营商的捷径 .

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

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

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

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

    CODE

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

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

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

    在对象中:

    ? anArgument
        ^ self
    

    在UndefinedObject(又名nil的类)中:

    ? anArgument
        ^ anArgument
    

    这有评估(?)和非评估版本(??) .
    在getter-methods中经常可以找到惰性初始化的私有(实例)变量,这些变量在真正需要之前保持为零 .

  • 9

    合并运算符

    它相当于

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

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

    你真正想要的是:

    return _formsAuthWrapper = _formsAuthWrapper ?? new FormsAuthenticationWrapper();
    

    要么

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

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

  • 8

    正如许多答案中正确指出的那样是"null coalescing operator"( ?? ),说到你可能还想看看它的堂兄"Null-conditional Operator"( ?.?[ )这是一个多次与 ?? 一起使用的算子

    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;
    

    这更冗长,更麻烦 .

  • 7

    注意:

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

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

    来源:

    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构造的类型没有被赋予有效的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 .

  • 0

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

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

    另一个有趣的观点是,"A nullable type can contain a value, or it can be undefined" . 因此,如果您尝试将可空值类型分配给不可为空的值类型,则会出现编译时错误 .

    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
    
  • 10
    FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();
    

    相当于

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

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

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

相关问题