我在c#6中编写了一段代码,并且由于一些奇怪的原因,这可以使用
var value = objectThatMayBeNull?.property;
但这不是:
int value = nullableInt?.Value;
如果不行,我的意思是我收到编译错误Cannot resolve symbol 'Value'
。
知道为什么空条件运算符?.
不起作用吗?
答案 0 :(得分:28)
好的,我做了一些思考和测试。这就是:
int value = nullableInt?.Value;
编译时给出此错误消息:
Type'int'不包含“Value”
的定义
这意味着?
'将int?
转换为实际的int
值。这实际上与:
int value = nullableInt ?? default(int);
结果是一个整数,显然没有Value
。
好的,这可能有帮助吗?
int value = nullableInt?;
不,不允许使用该语法。
那么呢?在这种情况下,请继续使用.GetValueOrDefault()
。
int value = nullableInt.GetValueOrDefault();
答案 1 :(得分:18)
原因是使用null条件运算符访问该值是没有意义的:
x?.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
。
答案 2 :(得分:7)
关于可空类型,?.
运算符正在说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
。 ?.
运算符在提取可空内容方面的表现类似。
对于您的具体示例,您应该使用??
运算符和适当的默认值而不是?.
运算符。
答案 3 :(得分:5)
我基本同意其他答案。我只是希望观察到的行为可以通过某种形式的权威文档来支持。
由于我无法在任何地方找到C#6.0规范(它出来了吗?),我找到的最接近“文档”的是C# Language Design Notes for Feb 3, 2014。假设那里发现的信息仍然反映了当前的事态,这里是正式解释观察到的行为的相关部分。
语义就像将三元运算符应用于空等式检查,空文字和运算符的无问题标记的应用程序,除了表达式只计算一次:
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
为{{ 1}}。 强>
将最后一条规则应用于:
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
。
C# Language Design Notes for Feb 3, 2014:
也正式涵盖了这一点结果的类型取决于底层运算符右侧的类型
int?
:
- 如果
T
(已知是)引用类型,则表达式的类型为T
- 如果
T
(已知是)非可空值类型,则表达式的类型为T
- 如果
T?
(已知是)可以为空的值类型,则表达式的类型为T
- 否则(即,如果不知道
T
是引用还是值类型),则表达式是编译时错误。
但是如果你被迫编写以下内容以使其编译:
T
...然后它似乎毫无意义,与简单的做法没有任何不同:
int? value = nullableInt?.Value;
正如其他人指出的那样,在您的情况下,您可能一直使用null-coalescing operator ??
,而不是null-conditional operator ?.
。
答案 4 :(得分:0)
int
没有Value
属性。
考虑:
var value = obj?.Property
相当于:
value = obj == null ? null : obj.Property;
对于int
没有任何意义,因此int?
没有通过?.
旧的GetValueOrDefault()
确实对int?
有意义。
或者就此而言,因为?
必须返回可以为空的东西,只需:
int? value = nullableInt;
答案 5 :(得分:0)
null条件运算符也会打开可以为null的变量。所以在“?”之后。运算符,不再需要“值”属性。
我写了一篇文章,详细介绍了我是如何遇到这个问题的。万一你想知道
http://www.ninjacrab.com/2016/09/11/c-how-the-null-conditional-operator-works-with-nullable-types/
答案 6 :(得分:0)
仅仅因为(基于以上的答案)
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'
出现语法错误时!