【问题标题】:Passing an uninitialised array to a method expecting a non-nullable IEnumerable doesn't cause a compilation warning or error [duplicate]将未初始化的数组传递给期望不可为空的 IEnumerable 的方法不会导致编译警告或错误 [重复]
【发布时间】:2020-09-14 10:35:02
【问题描述】:

在启用了可为空引用类型的 C# 8 中,为什么以下内容不会引发编译器警告或错误?

var strings = new string[1];
    
LogList(strings);
    
public void LogList(IEnumerable<string> strings) {
    foreach(var s in strings) {
        Console.WriteLine(s.ToString());
    }
}

我期待一个编译器警告或错误,因为数组有未初始化的元素,而 IEnumerable&lt;String&gt; 中的 String 是不可为空的。相反,当调用 s.ToString() 时,我会在运行时收到 NullReferenceException。

如果我指出数组元素可以为空,string?[],或者使用带有可以为空的字符串的集合,List&lt;string?&gt;,那么编译器会警告我将其传递给 LogList,它需要一个(非空)IEnumerable非空字符串。为什么上面的代码示例没有生成类似的警告?

我查看了一些关于可空引用类型的 SO 问题,但没有一个专门回答这个问题。

(在 LINQPad 6.9.15 中测试的代码)

【问题讨论】:

  • 涉及初始化的可空规则有许多例外,所有这些都围绕着现有的语义,例如数组和结构,它们具有隐式初始化。请参阅重复的,当然还有引用的文章,devblogs.microsoft.com/dotnet/…。简短的版本:C# 语言设计者认为对这些场景的警告会产生过多的误报,因此他们故意将它们排除在分析之外。您将数组声明为具有不可为空的元素,并且编译器相信您。所以没有警告。

标签: c# c#-8.0 nullable-reference-types


【解决方案1】:

在此代码var strings = new String[1]; 中,strings 不是 null,而是一个有效的 IEnumerable&lt;string&gt; 对象,其中第一个条目为 null。所以要使strings为空,你可以这样做string[] strings = null;

然后,当您通过启用可空引用类型来运行应用程序时,编译器不会抛出异常,而是会发出警告。 (如第一个屏幕截图所示)。

要将其视为错误,请将以下条目添加到 &lt;PropertyGroup&gt; 内的 .csproj 文件中

    <Nullable>enable</Nullable>
    <WarningsAsErrors>CS8600;CS8602;CS8603</WarningsAsErrors>

【讨论】:

  • 感谢您的回答。您提到了“一个有效的 IEnumerable 对象,其中第一个条目为空”,但我希望这仅作为 IEnumerable 有效。你能详细说明一下吗?
  • ok,这是泛型,泛型是特例。
  • 同样String[] 没有实现IEnumerable&lt;string?&gt;
  • 根据这篇文章,数组确实实现了 IEnumerable:docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/… - “数组类型是从抽象基类型 Array 派生的引用类型。由于该类型实现了 IEnumerable 和 IEnumerable,因此您可以使用 foreach C#中所有数组的迭代"
  • 泛型类型是特殊的,因为它们可以表示值类型(结构)和引用类型(类)。这意味着您不能使用 T? type 来表示可空类型,因为当泛型是值类型时,它会与现有的 Nullable 冲突。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多