2

我想知道为什么 Visual Studio 2019 不抱怨这段 C# 代码:

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

既然deserializedBody?.date可能null,那就意味着该ToString方法将应用于某事null。我认为是这样的:

deserializedBody?.date?.ToString();

将是正确的使用形式,但 Visual Studio 不会抱怨第一个版本。当然,我错过了关于这段代码的真实性质的一些东西。

4

1 回答 1

8

空安全解引用运算符一达到空值就停止对整个表达式的求值。所以如果deserializedBody为空,它不会尝试评估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 可空引用类型而期待警告,我相信动态表达式永远不会进行空检查。作为一个例子,考虑:

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开始时警告取消引用是有风险的,这似乎很奇怪。

于 2020-05-09T09:17:30.333 回答