Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么不';我没有得到一个关于C#8中null可能与结构的类成员解除引用的警告吗?_C#_Nullable_C# 8.0_Nullable Reference Types - Fatal编程技术网

为什么不';我没有得到一个关于C#8中null可能与结构的类成员解除引用的警告吗?

为什么不';我没有得到一个关于C#8中null可能与结构的类成员解除引用的警告吗?,c#,nullable,c#-8.0,nullable-reference-types,C#,Nullable,C# 8.0,Nullable Reference Types,在启用了的C#8项目中,我有以下代码,我认为这些代码应该给我一个关于可能的空解引用的警告,但没有: 公共类示例类成员 { 公共int值{get;} } 公共结构示例结构 { 公共示例类成员成员{get;} } 公共课程 { 公共静态void Main(字符串[]args) { var instance=newexamplestuct(); Console.WriteLine(instance.Member.Value);//此处预期会出现关于可能的空解引用的警告 } } 当使用默认构造函数初始

在启用了的C#8项目中,我有以下代码,我认为这些代码应该给我一个关于可能的空解引用的警告,但没有:

公共类示例类成员
{
公共int值{get;}
}
公共结构示例结构
{
公共示例类成员成员{get;}
}
公共课程
{
公共静态void Main(字符串[]args)
{
var instance=newexamplestuct();
Console.WriteLine(instance.Member.Value);//此处预期会出现关于可能的空解引用的警告
}
}

当使用默认构造函数初始化
instance
时,
instance.Member
被设置为
ExampleClassMember
的默认值,即
null
。因此,
instance.Member.Value
将在运行时抛出
NullReferenceException
。据我所知,C#8的可空性检测,我应该得到关于这种可能性的编译器警告,但我没有;这是为什么?

请注意,调用
控制台.WriteLine()
时没有理由发出警告。引用类型属性不是可为null的类型,因此编译器不需要警告它可能为null

您可能认为编译器应该警告
struct
本身中的引用。这对我来说似乎是合理的。但事实并非如此。这似乎是一个漏洞,由值类型的默认初始化引起,即必须始终有一个默认(无参数)构造函数,它总是将所有字段置零(引用类型字段为null,数字类型为零,等等)

我称之为漏洞,因为理论上不可为null的引用值实际上应该始终为非null!Duh.)

这篇博客文章似乎解决了这个漏洞:

避免空值 到目前为止,警告是关于保护可空引用中的空值不被取消引用。硬币的另一面是避免在不可空的引用中出现空值

空值存在的方式有两种,其中大多数值得注意,而其中的两种会导致另一个“警告之海”,最好避免:

  • 使用具有不可空引用类型字段的结构的默认构造函数。这是一个秘密,因为默认构造函数(将结构置零)甚至可以在许多地方隐式使用最好不要发出警告[emphasis mine-PD],否则许多现有结构类型将变得无用
换句话说,这是一个漏洞,但不是一个bug。语言设计者已经意识到了这一点,但他们选择将此场景排除在警告之外,因为考虑到
struct
初始化的工作方式,否则将不切实际

请注意,这也符合该功能背后更广泛的理念。同一条:

因此,我们希望它抱怨您现有的代码。但并不令人讨厌。以下是我们将如何努力实现这一平衡:

  • 即使您响应并消除了所有警告,也无法保证零安全。分析中有许多漏洞是出于必要,也有一些是出于选择
  • 最后一点:有时警告是“正确”的做法,但会一直对现有代码发出警告,即使它实际上是以空安全的方式编写的。在这种情况下,我们会犯方便的错误,而不是正确的错误。我们不能在现有代码上产生“警告之海”:太多人只会将警告关闭,永远不会从中受益

    还要注意,对于名义上不可为空的引用类型(例如
    string[]
    )的数组,也存在同样的问题。创建数组时,所有参考值均为
    null
    ,但这是合法的,不会生成任何警告


    这就是为什么事情是这样的原因。然后问题就变成了,该怎么办?这是非常主观的,我不认为有一个正确或错误的答案。也就是说

    我个人会根据具体情况处理我的
    struct
    类型。对于那些意图实际上是可空引用类型的对象,我将应用
    注释。否则,我不会

    从技术上讲,
    struct
    中的每一个引用值都应该是“可空的”,也就是说,在类型名称中包含
    可空的注释。但与许多类似的特性(如C#中的async/await或C++中的
    const
    )一样,这有一个“传染性”方面,即您以后需要重写该注释(使用
    注释),或者包括显式的空检查,或者只将该值分配给另一个可为空的引用类型变量

    对我来说,这破坏了启用可空引用类型的许多目的。由于
    struct
    类型的此类成员无论如何在某个时候都需要特殊的大小写处理,而且在仍然能够使用不可为空的引用类型的情况下,真正安全地处理它的唯一方法是在使用
    struct
    的任何地方进行空检查,我认为,当代码初始化
    结构时,代码有责任正确地进行初始化,并确保不可为null的引用类型成员实际上已初始化为非null值,这是一个合理的实现选择

    这可以通过提供一种“官方”的初始化方法来辅助,例如非默认构造函数(即带有参数的构造函数)或工厂方法。使用默认构造函数或根本不使用构造函数(如在数组分配中)仍然存在风险,但是通过提供c
    #nullable enable
    public class C
    {
        public int P1 { get; } 
    }
    
    public struct S
    {
        public C? Member { get; } // Reluctantly mark as nullable reference because
                                  // https://devblogs.microsoft.com/dotnet/nullable-reference-types-in-csharp/
                                  // states:
                                  // "Using the default constructor of a struct that has a
                                  // field of nonnullable reference type. This one is 
                                  // sneaky, since the default constructor (which zeroes 
                                  // out the struct) can even be implicitly used in many
                                  // places. Probably better not to warn, or else many
                                  // existing struct types would be rendered useless."
    }
    
    public class Program
    {
        public static void Main()
        {
            var instance = new S();
            Console.WriteLine(instance.Member.P1); // Warning
        }
    }