【问题标题】:Why doesn't Visual Studio warn me about a null reference exception?为什么 Visual Studio 没有就空引用异常向我发出警告?
【发布时间】:2020-05-09 09:15:07
【问题描述】:

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

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

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

deserializedBody?.date?.ToString();

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

【问题讨论】:

  • 这是一种简单、紧凑且非常便宜的方法来强制对象具有明确定义的日期值。例外是你的朋友。

标签: c# tostring nullable null-conditional-operator


【解决方案1】:

null 安全的解引用运算符一旦达到 null 就会停止对整个表达式的求值。所以如果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 是有风险的似乎很奇怪。

【讨论】:

  • ((dynamic)(JsonConvert.DeserializeObject("{}")))?.date.ToString()
  • @PauloMorgado:我不确定你的评论是想告诉我们什么。
  • date 属性可以并且是该代码上的null。编译器无法知道它不能是null。所以,它应该发出警告。
  • @PauloMorgado:您的意思是打开了可空引用类型?如果 NRT 使用动态类型进行任何操作,我会感到非常惊讶,因为否则每个尊重最终都需要?.
  • @PauloMorgado:我在答案中添加了一个示例和更多理由。
猜你喜欢
  • 1970-01-01
  • 2012-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-15
相关资源
最近更新 更多