C# 空条件运算符不使用可空类型?

C# 空条件运算符不使用可空类型?,c#,null-coalescing-operator,c#-6.0,C#,Null Coalescing Operator,C# 6.0,我正在用c#6编写一段代码,出于某种奇怪的原因,这是可行的 var value = objectThatMayBeNull?.property; 但这并不是: int value = nullableInt?.Value; “不工作”是指我得到一个编译错误,说无法解析符号“Value”。 知道为什么空条件运算符?。不起作用吗?int没有值属性 考虑: var value = obj?.Property 相当于: value = obj == null ? null : obj.Proper

我正在用c#6编写一段代码,出于某种奇怪的原因,这是可行的

var value = objectThatMayBeNull?.property;
但这并不是:

int value = nullableInt?.Value;
“不工作”是指我得到一个编译错误,说
无法解析符号“Value”

知道为什么空条件运算符
?。
不起作用吗?

int
没有
属性

考虑:

var value = obj?.Property
相当于:

value = obj == null ? null : obj.Property;
这对于
int
来说毫无意义,因此通过
使用
int?
就没有意义了。

旧的
GetValueOrDefault()
对于
int?
是有意义的

或者,由于
必须返回可为空的内容,因此只需:

int? value = nullableInt;

好的,我做了一些思考和测试。情况就是这样:

int value = nullableInt?.Value;
编译时给出此错误消息:

类型“int”不包含“Value”的定义

这意味着
int?
转换为实际的
int
值。这实际上与:

int value = nullableInt ?? default(int);
结果是一个整数,显然没有

好的,这有帮助吗

int value = nullableInt?;
不,不允许使用这种语法

那又怎样?对于这种情况,只需继续使用
.GetValueOrDefault()

int value = nullableInt.GetValueOrDefault();

关于可为null的类型,
?。
运算符表示
如果不为null,请使用包装值
。因此,对于可为null的int,如果可为null的值为
8
,则
的结果将是
8
,而不是包含
8
的可为null的值。由于
Value
不是
int
的属性,因此会出现错误

因此,尝试使用property
Value
的示例完全失败了,但下面的方法可行

var x=nullableInt?.ToString()

考虑空合并运算符,
??


var x=nullableInt??0;

这里,操作符说,
如果为null,则返回0,否则返回可为null的
中的值,在本例中,该值是一个
int
?。
运算符在提取可空值的内容方面执行类似的操作


对于您的特定示例,您应该使用
运算符和适当的默认值,而不是
运算符。

原因是使用空条件运算符访问值将毫无意义:

  • 当应用
    x?.p
    时,其中
    p
    是不可为空的值类型
    T
    ,结果为类型
    T?
    。出于同样的原因,
    nullableInt?.Value
    操作的结果必须可以为null
  • 当您的
    nullableInt
    具有值时,
    nullableInt?.value
    的结果将与值本身相同
  • 当您的
    null
    没有值时,结果将是
    null
    ,这与值本身相同
尽管使用
?。
运算符访问
没有意义,但访问可空值类型的其他属性也有意义。运算符与可空值类型和引用类型一致,因此这两种实现产生相同的行为:

class PointClass {
    public int X { get; }
    public int Y { get; }
    public PointClass(int x, int y) { X = x; Y = y; }
}
struct PointStruct {
    public int X { get; }
    public int Y { get; }
    public PointStruct(int x, int y) { X = x; Y = y; }
}
...
PointClass pc = ...
PointStruct? ps = ...
int? x = pc?.X;
int? y = ps?.Y;

在可为空的
结构
的情况下,运算符允许您访问基础类型
PointStruct
的属性,并以与引用类型
PointClass

的不可为空属性相同的方式将可为空性添加到结果中。我基本上同意其他答案。我只是希望观察到的行为能够得到某种形式的权威文件的支持

由于我在任何地方都找不到C#6.0规范(是否已经发布了?),因此我发现最接近“文档”的是。假设在那里发现的信息仍然反映了当前的情况,下面是正式解释观察到的行为的相关部分

语义类似于将三元运算符应用于空等式检查、空文本和运算符的无问号应用程序,只是表达式只计算一次:

e?.m(…)   =>   ((e == null) ? null : e0.m(…))
e?.x      =>   ((e == null) ? null : e0.x)
e?.$x     =>   ((e == null) ? null : e0.$x)
e?[…]     =>   ((e == null) ? null : e0[…])
其中
e0
e
相同,除非
e
是可空值类型,在这种情况下
e0
e.value

将最后一条规则适用于:

nullableInt?.Value
。。。语义等价的表达式变为:

((nullableInt == null) ? null : nullableInt.Value.Value)
显然,
nullableInt.Value.Value
无法编译,这就是您观察到的

至于为什么设计决定将特殊规则应用于可空类型,我认为
dasblinkenlight
的回答很好地涵盖了这一点,所以我不在这里重复


此外,我应该提到,即使假设我们没有针对可空类型的特殊规则,并且表达式
nullableInt?.Value
的编译和行为与您最初认为的一样

// let's pretend that it actually gets converted to this...
((nullableInt == null) ? null : nullableInt.Value)
但是,您的问题中的以下陈述将无效并产生编译错误:

int value = nullableInt?.Value; // still would not compile
它仍然不起作用的原因是
nullableInt?.Value
表达式的类型是
int?
,而不是
int
。因此,您需要将
变量的类型更改为
int?

这也正式包含在以下内容中:

结果的类型取决于基础运算符右侧的类型
T

  • 如果
    T
    是(已知的)引用类型,则表达式的类型是
    T
  • 如果
    T
    是(已知的)不可为空的值类型,则表达式的类型是
    T?
  • 如果
    T
    是(已知的)可空值类型,则表达式的类型为
    T
  • 否则
    int? value = nullableInt?.Value;
    
    int? value = nullableInt;
    
    var value = objectThatMayBeNull?.property;
    
    var value = (objectThatMayBeNull == null) ? null : objectThatMayBeNull.property
    
    int value = nullableInt?.Value;
    
    int value = (nullableInt == null) ? null : nullableInt.Value.Value;