[英]null conditional operator not working with nullable types?
我在c#6中编写了一段代码,并且出于一些奇怪的原因,这是有效的
var value = objectThatMayBeNull?.property;
但这不是:
int value = nullableInt?.Value;
通过不工作我的意思是我得到一个编译错误说Cannot resolve symbol 'Value'
。 知道为什么null条件运算符?.
不工作?
好的,我做了一些思考和测试。 这是发生的事情:
int value = nullableInt?.Value;
编译时给出此错误消息:
类型'int'不包含`Value'的定义
那意味着?
'转换' int?
进入实际的int
值。 这实际上与:
int value = nullableInt ?? default(int);
结果是一个整数,显然没有Value
。
好的,这可能有帮助吗?
int value = nullableInt?;
不,不允许使用该语法。
那么呢? 在这种情况下继续使用.GetValueOrDefault()
。
int value = nullableInt.GetValueOrDefault();
这样做的原因是使用null条件运算符访问该值是没有意义的:
x?.p
p
,其中p
是一个非可空值类型T
,结果是T?
。 出于同样的原因, nullableInt?.Value
操作的结果必须是可空的。 Nullable<T>
有一个值时, nullableInt?.Value
的结果将与值本身相同 Nullable<T>
没有值时,结果将为null
,这又与值本身相同。 虽然使用?.
访问Value
是没有意义的?.
运算符,访问可空值类型的其他属性确实有意义。 运算符与可空值类型和引用类型一致,因此这两个实现产生相同的行为:
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
的情况下,运算符允许您访问基础类型PointStruct
的属性,并且它以与对引用类型PointClass
非可空属性相同的方式添加结果的可空性。
关于可空类型, ?.
运算符说if not null, use the wrapped value
。 因此,对于可空的int,如果可空值为8
,则结果为?.
将是8
,而不是包含8
的可空。 由于Value
不是int
的属性,因此会出错。
因此,尝试使用属性Value
的示例完全失败,但以下方法可行,
var x = nullableInt?.ToString();
考虑null-coalescing运算符, ??
。
var x = nullableInt ?? 0;
这里,运算符说, if null, return 0, otherwise return the value inside the nullable
,在本例中为int
。 ?.
运算符在提取可空的内容方面表现相似。
对于您的具体示例,您应该使用??
运算符和适当的默认值而不是?.
运营商。
我基本同意其他答案。 我只是希望观察到的行为可以通过某种形式的权威文档来支持。
由于我无法在任何地方找到C#6.0规范(它出来了吗?),我发现的最接近“文档”的是2014年2月3日的C#语言设计说明 。 假设在那里找到的信息仍然反映了当前的事态,这里是正式解释观察到的行为的相关部分。
语义就像将三元运算符应用于空等式检查,空文字和运算符的非问题标记应用程序,除了表达式仅计算一次:
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
。 那么你需要将value
变量的类型更改为int?
。
结果的类型取决于底层运算符右侧的类型
T
:
- 如果
T
(已知是)引用类型,则表达式的类型为T
- 如果
T
(已知是)非可空值类型,则表达式的类型为T?
- 如果
T
(已知是)可空值类型,则表达式的类型为T
- 否则(即,如果不知道
T
是引用还是值类型),则表达式是编译时错误。
但是,如果您将被迫编写以下内容以使其编译:
int? value = nullableInt?.Value;
......然后它似乎毫无意义,与简单地做完就没有什么不同:
int? value = nullableInt;
正如其他人所指出的那样,在你的情况下,你可能想要使用null-coalescing运算符??
一直以来,不是空条件运算符?.
。
int
没有Value
属性。
考虑:
var value = obj?.Property
相当于:
value = obj == null ? null : obj.Property;
这对int
没有意义,因此没有int?
通过?.
旧的GetValueOrDefault()
虽然对int?
有意义int?
。
或者就此而言,从那以后?
必须返回可以为空的东西,简单地说:
int? value = nullableInt;
null条件运算符也会打开可以为null的变量。 所以在“?”之后。 运算符,不再需要“值”属性。
我写了一篇文章,详细介绍了我是如何遇到这个问题的。 如果你想知道
http://www.ninjacrab.com/2016/09/11/c-how-the-null-conditional-operator-works-with-nullable-types/
仅仅因为(基于上面的sstan答案)
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'
语法错误!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.