为什么 Visual Studio 不警告我空引用异常?

Why doesn't Visual Studio warn me about a null reference exception?

不知为什么Visual Studio2019不吐槽这段C#代码:

dynamic deserializedBody = JsonConvert.DeserializeObject(requestBody);
deserializedBody?.date.ToString();

由于 deserializedBody?.date 可能是 null,这意味着 ToString 方法将应用于某些 null。我认为是这样的:

deserializedBody?.date?.ToString();

将是正确的使用形式,但 Visual Studio 不会抱怨第一个版本。我肯定错过了这段代码的真实本质。

null 安全取消引用运算符在遇到 null 时立即停止对整个表达式的求值。因此,如果 deserializedBody 为 null,它不会尝试计算 date,也不会调用 ToString() 任何东西 - 所以你不会得到异常。

完整示例:

using System;

class Test
{
    DateTime date = DateTime.UtcNow;

    static void Main()
    {
        Test t = null;
        // No exception thrown
        Console.WriteLine(t?.date.ToString());
    }    
}

这里的表达式t?.date.ToString()等同于:

t is null ? null : t.date.ToString()

(除了 t 只计算一次)。 等同于

(t is null ? null : t.date).ToString()

...这就是我怀疑您期望它做的事情。

但是不,这个 不会 防止 deserializedBody 为非空,但 deserializedBody.date 为空的情况。

如果您期望由于 C# 8 可为 null 的引用类型而收到警告,我相信动态表达式永远不会进行 null 检查。例如,请考虑:

class Test
{
    public string? foo;
}

class Program
{
    static void Main(string[] args)
    {
        Test t = new Test();
        dynamic d = t;

        Console.WriteLine(t.foo.Length); // Warning 
        Console.WriteLine(d.foo.Length); // No warning
        Console.WriteLine(d.bar); // No warning for this either
    }
}

怀疑这是因为编译器基本上没有关于d.foo是什么的信息。对于每一个有有用警告的情况,都会有另一种情况警告没有用。当您处于动态类型领域时,您已经接受了一定程度的风险 - 当 d.foo 的访问一开始就有风险时,警告取消引用 d.foo 是有风险的似乎很奇怪。