null条件运算符不能使用可为空的types吗?
我在c#6中写了一段代码,出于一些奇怪的原因
var value = objectThatMayBeNull?.property; 但是这不是:
 int value = nullableInt?.Value; 
 通过不工作,我的意思是我得到一个编译错误,说Cannot resolve symbol 'Value' 。 任何想法为什么空条件运算符?. 不工作? 
好吧,我已经做了一些思考和testing。 这是发生了什么事情:
 int value = nullableInt?.Value; 
编译时出现此错误消息:
types“int”不包含“Value”的定义
 那意味着?  '转换' int? 进入实际的int值。 这实际上是一样的: 
 int value = nullableInt ?? default(int); 
 结果是一个整数,显然没有一个Value 。 
好的,这可能有帮助吗?
 int value = nullableInt?; 
不,这个语法是不允许的。
 那么呢? 只要继续使用.GetValueOrDefault()这种情况。 
 int value = nullableInt.GetValueOrDefault(); 
原因是用一个空的条件运算符访问值是没有意义的:
-  当你应用x?.pp,其中p是一个不可为空值的typesT,结果是T?。 同样,nullableInt?.Value操作的结果必须是可空的。
-  当你的Nullable<T>有一个值的时候,nullableInt?.Value的结果和它本身的值是一样的
-  当你的Nullable<T>没有值的时候,结果会是null,也就是这个值本身。
 尽pipe用“ ?.来访问Value是没有意义的?. 运算符,它是有道理的访问可空值types的其他属性。 运算符一致地使用可为空的值types和引用types,所以这两个实现产生相同的行为: 
 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; 
 在可空struct的情况下,运算符允许您访问基础typesPointStruct的属性,并且以与引用typesPointClass不可为null属性相同的方式向结果添加可空性。 
 关于可空types, ?. 运算符说if not null, use the wrapped value 。 因此,对于一个可空的int,如果可为空的值为8 ,那么?.的结果?. 将是8 ,而不是包含8的可为空。 由于Value不是int的属性,所以会出错。 
 所以,试图使用财产Value的例子是正确的失败,但下面的工作, 
 var x = nullableInt?.ToString(); 
 考虑空合并运算符??  。 
 var x = nullableInt ?? 0; 
 在这里,运算符说, if null, return 0, otherwise return the value inside the nullable ,在这种情况下是int 。 那个?. 运算符在提取可为空的内容方面也是类似的。 
 对于你的具体例子,你应该使用?? 运算符和适当的默认值而不是?. 运营商。 
我基本上同意其他答案。 我只是希望观察到的行为可以通过某种forms的权威文件来支持。
由于我无法在任何地方findC#6.0规范(是否已经出来?),最接近我发现的“文档”是2014年2月3日的C#语言devise说明 。 假设在那里发现的信息仍然反映了当前的情况,下面是正式解释观察到的行为的相关部分。
语义就像应用三元运算符到一个空的相等性检查,一个空文本和一个没有问题标记的运算符的应用程序,除了expression式只被计算一次:
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是可空值types,在这种情况下e0是e.Value。
将最后一条规则应用于:
 nullableInt?.Value 
…语义等价的expression式变成:
 ((nullableInt == null) ? null : nullableInt.Value.Value) 
 显然, nullableInt.Value.Value无法编译,这就是你所观察到的。 
 至于为什么devise决定将这个特殊规则应用于可空types,我认为dasblinkenlight的答案很好地覆盖了这个,所以在这里我不再重复。 
 此外,我应该提到,即使假设我们没有这个可为空的types的特殊规则,并且expression式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?.Valueexpression式的types是int?  ,而不是int 。 所以你需要改变valuevariables的types为int?  。 
2014年2月3日的“ C#语言devise手册”也对此进行了正式的介绍:
结果的types取决于底层运算符右侧的types
T:
- 如果
T(已知是)引用types,则expression式的types是T- 如果
T(已知是)不可空值types,则expression式的types是T?- 如果
T(已知)是可以为空的值types,则expression式的types为T- 否则(即如果不知道
T是一个引用还是值types)expression式是编译时错误。
但是,如果你将被迫编写以下内容来编译它:
 int? value = nullableInt?.Value; 
那么这似乎是毫无意义的,和简单的做法没有什么两样:
 int? value = nullableInt; 
 正如其他人指出的,在你的情况下,你可能打算使用空合并运算符?? 一直以来,不是空条件运算符?.  。 
null条件运算符还打开可空的variables。 所以在“?”之后。 运营商,“价值”属性不再需要。
我写了一篇关于如何处理这个问题的文章。 如果你想知道
http://www.ninjacrab.com/2016/09/11/c-how-the-null-conditional-operator-works-with-nullable-types/
只是因为(基于上面的斯坦答案)
 var value = objectThatMayBeNull?.property; 
由编译器来评估
 var value = (objectThatMayBeNull == null) ? null : objectThatMayBeNull.property 
和
 int value = nullableInt?.Value; 
喜欢
 int value = (nullableInt == null) ? null : nullableInt.Value.Value; 
 当nullableInt.Value.Value是Cannot resolve symbol 'Value'语法错误! 
  int没有Value属性。 
考虑:
 var value = obj?.Property 
相当于:
 value = obj == null ? null : obj.Property; 
 这对int来说是没有意义的,因此不是int? 通过?. 
 旧的GetValueOrDefault()虽然有意义与int?  。 
 或者就此而言,因为? 必须返回可空的,只是: 
 int? value = nullableInt;