繁体   English   中英

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

[英]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[…]) 

其中e0e相同, 除非e是可空值类型,在这种情况下e0e.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运算符?? 一直以来,不是空条件运算符?.

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.ValueCannot resolve symbol 'Value'语法错误!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM