21

我一直感兴趣地关注 C#6 中添加的安全导航运算符功能。我已经期待了一段时间了。但我发现一些与我预期不同的行为。我意识到我真的不明白它是如何工作的。

鉴于这个类

class Foo {
    public int? Measure;
}

这是一些使用 new 运算符的代码。

Foo f = new Foo { Measure = 3 };
Console.WriteLine(f?.Measure);  // 3

f = new Foo { Measure = null };
Console.WriteLine(f?.Measure);  // null

f = null;
Console.WriteLine(f?.Measure);  // null

到这里为止,一切都按预期工作。 ?.当左侧不为 null 时正在访问成员,否则返回 null。但这里的事情朝着我没想到的方向发展。

var i = f?.Measure; // i is Nullable<int>
Console.WriteLine(i.HasValue); // false
Console.WriteLine(f?.Measure.HasValue); // null

什么?

为什么我可以从我分配给的同一个表达式中得到HasValuei但不能得到i?怎么可能HasValue是空的?

编辑:我真正的问题是关于程序行为,而不是编译错误。我删除了关于编译的额外内容,并将这个问题更狭隘地集中在为什么看似相同的逻辑会返回两个不同的结果。

4

4 回答 4

21

让我们从逻辑上分析一下。

var f = ???;
var i = f?.Measure;
var t = i.HasValue;

我们不知道是否f为空。

  1. 如果f null,则结果 ( i) 为null
  2. 如果f 不为空,则结果 ( i) 是int

因此,i定义为int?,并且tbool

现在,让我们来看看这个:

var f = ???;
var i = f?.Measure.HasValue;
  1. 如果f null,则结果 ( i) 为 null
  2. 如果f 不为null,则结果 ( i) 为Measure.HasValue,这是一个布尔值。

因此,i是一个bool?

如果f为null,我们短路并返回null。如果不是,我们返回 的bool结果.HasValue

本质上,使用?.- 时,返回类型必须是引用值或 a Nullable<T>,因为表达式可能会短路以返回 null。

于 2015-08-28T02:25:34.420 回答
2
var i = f?.Measure; // i is Nullable<int>
Console.WriteLine(i.HasValue); // false
Console.WriteLine(f?.Measure.HasValue); // null

在这种情况下,f 为空。

i.HasValue返回的原因false是因为i是 type Nullable<int>。因此,即使 的值为i空,就像在这种情况下一样,i.HasValue仍然可以访问。

但是,在评估后f?.Measure.HasValue立即返回。因此,您在上面看到的结果。nullf?

引用Rob 的评论

要意识到的主要事情是你正在阅读和理解这个:f?.Measure.HasValue 是这样的:(f?.Measure).HasValue,它不是。

于 2017-02-23T19:43:58.247 回答
0

Nullable<T>实际上是一个结构,因此不能为空,只有它Value可以,所以HasValue总是可以访问的。

于 2015-08-28T01:41:56.600 回答
0

我今天遇到了这个。

以下 C# 代码段打印了什么?

public class NullTests
{
    public static void Main(string[] args)
    {
        object obj = DoIt();
        Console.WriteLine(obj?.ToString().NullToNothing());
    }

    private static object DoIt() => null;
}

public static class Extensions
{
    public static string NullToNothing(this string input) => input ?? "nothing";
}

答案:

以下 Kotlin 代码段打印了什么?

fun main() {
    val obj = doIt()
    println(obj?.toString().NullToNothing())
}

fun doIt() = null
fun String?.NullToNothing() = this ?: "nothing"

答案:“没什么”

像你一样,我期待 Kotlin 的行为,这让我在一天中的大部分时间里都被绊倒了。:(

于 2020-03-11T20:50:36.747 回答