为什么要针对null检查不可为null的类型实际上在C#8中进行编译

问题描述 投票:0回答:1

我正在尝试在C#8.0中使用可空引用类型。我已经设置了一个示例代码对其进行测试,但是有些事情使我感到困惑!

据我了解,当我们?加到Type时,它被视为不可为空。那么,为什么在Main()方法中,编译器没有抱怨我要对照myClass检查null?在编译器看来myClass是不可为空的吗?

#nullable enable
using System;

namespace ConsoleApp4
{
    class Program
    {     
        static void Main()
        {
            var service = new Service();
            MyClass myClass  = service.GetMyClass();

            // I am curious why this line compiles!
            if (myClass == null)
            {
                throw new ArgumentNullException();
            }
        }
    }

    public sealed class Service
    {
        private MyClass? _obj;

        public MyClass GetMyClass()
        {
            if (_obj == null)
            {
                _obj = new MyClass();
            }

            return _obj;
        }
    }

    public sealed class MyClass
    {
    }
}
c# nullable c#-8.0 non-nullable
1个回答
0
投票

至此,对于编译器来说,myClass是不可为空的吗?

确实是这样。将鼠标悬停在无效检查上的myClass上,静态分析的工具提示将告诉您myClass在此处不为空。

所以,为什么要检查它是否为null?因为你能。它仍然是引用类型。它不会为null的事实未在类型中进行注释。

此外,请注意,它并没有告诉您异常不是可到达的代码。为什么会这样?

嗯,C#8.0可为空的引用不是万无一失的。它们在大多数情况下都足够好。但是,有时会出现一些无法识别的模式。需要注释和允许空值的运算符(!)。您可以使用哪个来告诉编译器何时您更了解。但是,这些让编译器可以说谎:

public MyClass GetMyClass()
{
    return _obj!;
}

类似地,根据静态编译器,您可以检查某些内容是否为null。因为您更了解:

public sealed class Service
{
    private MyClass? _obj;

    public MyClass GetMyClass()
    {
        return _obj!;
    }
}

internal static class Program
{
    private static void Main()
    {
        var service = new Service();
        var myClass = service.GetMyClass();

        // I am curious why this line compiles!
        if (myClass == null)
        {
            throw new ArgumentNullException();
        }
    }
}

当然,我不建议您继续对编译器撒谎。但是,如果您从第三方接收参数,建议仍然进行空检查。同样,当使用公共API时,您将无法信任实现。

© www.soinside.com 2019 - 2024. All rights reserved.