C# 运算符?、??=、 ?、??、?: 各种问号的用法及说明 - 图1

可空类型修饰符(?):

引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空,例如:string str=null;是正确的。int i=null;编译器将报错。为了使值类型也可为空,可空类型出现了,可空类型使用可空类型修饰符?来表示,表现形式为T?。例:int?表示是可空的整形,DateTime?表示为可空的时间。T?其实是System.Nullable(泛型结构)的缩写形式,也就意味着当你用到T?时编译器在编译时会把T?编译成System.Nullable的形式,例如:int?,编译后便是System.Nullable的形式。

  1. int a; //a<>null
  2. int ?b; //b=null
  3. int ?c = b+1; //c=null;

空合并运算符(??):

用于定义可空类型和引用类型的默认值。如果此运算符的左操作数不为 null,则此运算符将返回左操作数;否则返回右操作数。 例:a??b,当a为null时则返回b,a不为空时返回a本身。空合并运算符为右结合运算符,即操作时从右向左进行组合的。如,“a??b??c”的形式按“a??(b??c)”计算。

  1. int?a=null; int b;(声明ab)
  2. b=a??2; //b=2;
  3. a=6;b=a??8;//b=6;

三元(运算符)表达式(?:)

条件运算符 (?:) 通常被称为三元条件运算符,用于计算 Boolean 表达式,并根据 Boolean 表达式的计算结果为 true 还是 false 来返回计算两个表达式其中之一的结果。
int a=1>0?1:0 //a=1;

null 合并赋值运算符 ??=

适用于 C# 8.0 及更高版本,只有在左操作数计算为 null 时,null 合并赋值运算符 ??= 才将其右操作数的值分配给左操作数。 如果左操作数的计算结果为非 null,则 ??= 运算符不会计算其右操作数。

  1. List<int> numbers = null;
  2. int? a = null;
  3. (numbers ??= new List<int>()).Add(5);
  4. Console.WriteLine(string.Join(" ", numbers)); // output: 5
  5. numbers.Add(a ??= 0);
  6. Console.WriteLine(string.Join(" ", numbers)); // output: 5 0
  7. Console.WriteLine(a); // output: 0

Null 条件运算符 ?. 和 ?[]

Null 条件运算符在 C# 6 及更高版本中可用,仅当操作数的计算结果为非 null 时,null 条件运算符才会将成员访问 ?. 或元素访问 ?[] 运算应用于其操作数。 如果操作数的计算结果为 null,则应用运算符的结果为 null。 Null 条件成员访问运算符 ?. 也称为 Elvis 运算符。
NULL 条件运算符采用最小化求值策略。 也就是说,如果条件成员或元素访问运算链中的一个运算返回 null,则链的其余部分不会执行。 在以下示例中,如果 A 的计算结果为 null,则不会计算 B;如果 A 或 B 的计算结果为 null,则不会计算 C:

  1. double SumNumbers(List<double[]> setsOfNumbers, int indexOfSetToSum)
  2. {
  3. return setsOfNumbers?[indexOfSetToSum]?.Sum() ?? double.NaN;
  4. }
  5. var sum1 = SumNumbers(null, 0);
  6. Console.WriteLine(sum1); // output: NaN
  7. var numberSets = new List<double[]>
  8. {
  9. new[] { 1.0, 2.0, 3.0 },
  10. null
  11. };
  12. var sum2 = SumNumbers(numberSets, 0);
  13. Console.WriteLine(sum2); // output: 6
  14. var sum3 = SumNumbers(numberSets, 1);
  15. Console.WriteLine(sum3); // output: NaN