C# 安全导航运算符 - 实际发生了什么?

C# Safe navigation operator - what is actually going on?

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

鉴于此 class

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

到目前为止,一切都按预期进行。 ?. 当左边不为空时访问成员,否则返回空。但是这里的事情朝着我没想到的方向发展。

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

什么?

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

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

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

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

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

我们不知道 f 是否为空。

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

因此,i定义为int?,而t是一个bool

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

var f = ???;
var i = f?.Measure.HasValue;
  1. 如果f null,那么结果(i)是null
  2. 如果 f 不是 null,则结果 (i) 是 Measure.HasValue,这是一个 bool。

因此,i是一个bool?

如果f 为空,我们短路并且return 为空。如果不是,我们 return .HasValuebool 结果。

本质上,当使用 ?. 时 - return 类型 必须 是一个参考值,或者 Nullable<T>,因为表达式可以对 return null.

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

在这种情况下,f 为空。

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

然而,f?.Measure.HasValuef? 之后立即 returns null 被评估。因此,您在上面看到的结果。

只是引用 :

The main thing to realise is that you're reading and understanding this: f?.Measure.HasValue as this: (f?.Measure).HasValue, which it's not.

今天我运行进入这个。

下面的 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"

答案:"nothing".

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