我正在使用C#6编写一段代码,出于某种奇怪的原因这个代码可以运行
var value = objectThatMayBeNull?.property;
但是这个不会:
int value = nullableInt?.Value;
当我说“不起作用”时,我的意思是我收到了一个编译错误,上面写着Cannot resolve symbol 'Value'
。
你有什么想法,为什么空值条件运算符?.
不能正常工作?
我正在使用C#6编写一段代码,出于某种奇怪的原因这个代码可以运行
var value = objectThatMayBeNull?.property;
但是这个不会:
int value = nullableInt?.Value;
当我说“不起作用”时,我的意思是我收到了一个编译错误,上面写着Cannot resolve symbol 'Value'
。
你有什么想法,为什么空值条件运算符?.
不能正常工作?
好的,我进行了一些思考和测试。这就是发生的事情:
int value = nullableInt?.Value;
编译时出现以下错误信息:
类型“int”不包含名为“Value”的定义
这意味着?
将int?
转换为实际的int
值。这与以下代码的效果相同:
int value = nullableInt ?? default(int);
结果是一个整数,显然它没有“Value”。
好的,这可能有帮助吗?
int value = nullableInt?;
不,那种语法是不允许的。
那么怎么办呢?对于这种情况,只需继续使用 .GetValueOrDefault()
。
int value = nullableInt.GetValueOrDefault();
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
的非可空属性相同的方式将nullability添加到结果中。
?.
解析为包装的 int
类型,而不是可空类型本身。 - Jeff Yates?.
的结果是其中的实际 int
,它没有 Value
或 HasValue
属性。就像我的答案中所述,尝试使用 nullableInt?.ToString()
。 - Jeff YatesDateTime? dt=DateTime.Now; int? day=dt?.Day;
. 在?.
之后应该是DateTime
的属性而不是DateTime?
的属性。 - user4003407int
。所以 someInt?.XXX
的最终结果与 someInt.GetValueOrDefault().XXX
相同。 - Patrick HofmansomeInt.HasValue ? someInt.GetValueOrDefault().XXX : null
- Ben Voigt?.
操作符的意思是 如果不为空,则使用包装的值
。因此对于可空的 int 类型,如果可空类型有值 8
,则 ?.
的结果将是 8
,而不是包含 8
的可空类型。由于 Value
不是 int
的属性,因此会出现错误。Value
的示例完全失败,但以下内容可以正常工作:
var x = nullableInt?.ToString();
考虑到空合并运算符 ??
。
var x = nullableInt ?? 0;
在这里,操作符表示 如果为空,则返回 0,否则返回可空类型内部的值
,在这种情况下,它是一个 int
。与提取可空类型的内容类似,?.
操作符执行得也相似。??
运算符和适当的默认值,而不是 ?.
运算符。var x = nullableInt ?? 0
无法编译,因为 nullableInt
和 0
是不同的类型:分别是 Nullable<int>
和 int
。你必须使用 nullableInt.GetValueOrDefault(0)
或者 nullableInt.GetValueOrDefault()
,因为 default(int)
就是 0
。 - Suncat2000将最后一条规则应用于:The semantics are like applying the ternary operator to a null equality check, a null literal and a non-question-marked application of the operator, except that the expression is evaluated only once:
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[…])
Where
e0
is the same ase
, except ife
is of a nullable value type, in which casee0
ise.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?
。
这也在2014年2月3日C#语言设计注释中正式涵盖:
结果类型取决于底层操作符右侧的类型T: - 如果T是已知的引用类型,则表达式的类型为T。 - 如果T是已知的非空值类型,则表达式的类型为T?。 - 如果T是已知的可空值类型,则表达式的类型为T。 - 否则(即不知道T是引用类型还是值类型),表达式是编译时错误。int? value = nullableInt?.Value;
如果是这样,那么似乎毫无意义,与仅仅执行以下操作没有任何区别:
int? value = nullableInt;
正如其他人所指出的,在您的情况下,您可能本来就是想使用 null-coalescing运算符??
,而不是null-conditional运算符?.
。
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'
语法错误时!空值条件运算符还可以解包可空变量。因此,在“?.”运算符之后,“Value”属性就不再需要了。
我写了一篇文章,详细介绍了我是如何发现这个问题的。如果你感兴趣的话。
http://www.ninjacrab.com/2016/09/11/c-how-the-null-conditional-operator-works-with-nullable-types/
int
没有 Value
属性。
请考虑:
var value = obj?.Property
等同于:
value = obj == null ? null : obj.Property;
这在使用 int
时没有意义,因此也不适用于 int?
,可以使用 ?.
。
旧的 GetValueOrDefault()
在使用 int?
时确实有意义。
或者说,由于 ?
必须返回可空类型,因此可以简单地使用:
int? value = nullableInt;
??
运算符,例如nullableInt ?? 0
。 - Jeff Yates