可空引用类型的注释只能在“#nullable”上下文中的代码中使用

Posted

技术标签:

【中文标题】可空引用类型的注释只能在“#nullable”上下文中的代码中使用【英文标题】:The annotation for nullable reference types should only be used in code within a '#nullable' context 【发布时间】:2019-08-24 19:24:59 【问题描述】:

我有一个控制台应用程序来试用 C# 8 空引用类型。将项目切换为使用 lang ver C# 8 构建。

那么下面的代码会产生一个警告。

 class Program
    
        static void Main(string[] args)
        
            string? message = "Hello World";
            string message2 = null;

            Console.WriteLine(message);
            Console.WriteLine(message2);

            // The annotation for nullable reference types should only be used in code within a '#nullable' context
        
    

这究竟是什么意思?

【问题讨论】:

【参考方案1】:

对于任何在这里结束的人。 您可以按照@Marc 在 cmets 中的建议,将#nullable enable 放在文件顶部,以实现逐个文件的方法。

您还可以使用#nullable enable/disable 的组合来仅注释文件的某些部分

class Program

    static void Main(string[] args)
    
#nullable enable
        string? message = "Hello World";
#nullable disable
        string message2 = null;

        Console.WriteLine(message);
        Console.WriteLine(message2);
    

这是文档的链接。 https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references#nullable-contexts

可空上下文支持对编译器解释引用类型变量的方式进行细粒度控制。任何给定源代码行的 可为空的注释上下文 被启用或禁用。您可以将 C# 8.0 之前的编译器视为在禁用的可空上下文中编译所有代码:任何引用类型都可能为空。 可为空的警告上下文 也可以启用或禁用。可为空的警告上下文指定编译器使用其流分析生成的警告。

可以使用.csproj 文件中的 Nullable 元素为项目设置可为空的注释上下文和可为空的警告上下文。此元素配置编译器如何解释类​​型的可空性以及生成哪些警告。有效设置为:

enable: 可空注释上下文已启用。可空警告上下文已启用。 引用类型的变量,例如string,是不可为空的。所有可空性警告均已启用。 warnings: 可空注释上下文已禁用。可空警告上下文已启用。 引用类型的变量是不经意的。所有可空性警告均已启用。 annotations: 可空注释上下文已启用。可空警告上下文已禁用。 引用类型的变量,例如string,是不可为空的。所有可空性警告均已禁用。 disable: 可空注释上下文已禁用。可空警告上下文已禁用。 引用类型的变量是无意识的,就像 C# 的早期版本一样。所有可空性警告均已禁用。

在您的.csproj 文件中,只需在相关的<PropertyGroup> 元素中添加<Nullable>enable</Nullable>(您的项目文件可能为每个项目配置名称具有单独的<PropertyGroup> 元素)。

所以你的项目文件应该是这样的:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

</Project>

要将可为空的消息显示为错误而不是警告,请将其添加到您的项目文件中:

&lt;WarningsAsErrors&gt;CS8600;CS8602;CS8603&lt;/WarningsAsErrors&gt;

...像这样:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
    <Nullable>enable</Nullable>
    <WarningsAsErrors>CS8600;CS8602;CS8603</WarningsAsErrors>
  </PropertyGroup>

</Project>

对应的完整消息是:

CS8600:将 null 文字或可能的 null 值转换为不可为 null 的类型。 CS8602:可能取消引用空引用。 CS8603:可能返回空引用。

您还可以使用指令在项目的任何位置设置这些相同的上下文:

#nullable enable:将可空注释上下文和可空警告上下文设置为启用。 #nullable disable:将可空注释上下文和可空警告上下文设置为禁用。 #nullable restore:将可为空的注释上下文和可为空的警告上下文恢复到项目设置中。 #nullable disable warnings:将可为空的警告上下文设置为禁用。 #nullable enable warnings:将可为空的警告上下文设置为启用。 #nullable restore warnings:将可为空的警告上下文恢复到项目设置。 #nullable disable annotations:将可为空的注释上下文设置为禁用。 #nullable enable annotations:将可空注释上下文设置为启用。 #nullable restore annotations:将注释警告上下文恢复到项目设置中。

默认情况下,可为空的注释和警告上下文被禁用。这意味着您现有的代码无需更改且不会生成任何新警告即可编译。

请注意,C# 8.0 和 Visual Studio 2019 的预发布版本也支持 safeonly,但 this option has since been removed 并不存在于最终发布的 C# 8.0 中。此外,预发布版本使用#pragma warning restore nullable,但发布版本使用#nullable restore warnings

【讨论】:

不错的答案;我喜欢它涵盖两种方法 可能还值得扩展以涵盖 #nullable disable#nullable restore 或指向涵盖所有这些的文档的链接。 答案已编辑以反映在 VS 16.1 中将属性 NullableContextOptions 重命名为 Nullable 好答案。但由于某种原因,改变项目参数的方法对我不起作用。使用 Visual Studio 代码。 我的 csproj 中有这个,所以我不需要在代码中添加任何额外内容 enable 但我仍然收到错误【参考方案2】:

我也遇到了同样的错误,我花了几天的时间来解决它,原因没有在其他答案中描述:Roslyn C# 编译器中有特殊的(未记录的?)规则用于生成的代码 em> 使用可空功能,并且在我将 Visual Studio 2019 升级到最新版本(16.4+)之前,错误消息与上面的无用消息完全相同——尽管我的项目文件中有 &lt;Nullable&gt;enabled&lt;/Nullable&gt;

但在最新版本的 Visual Studio 2019 中,他们已将错误消息升级为:

警告 CS8669:可空引用类型的注释只能在“#nullable”注释上下文中的代码中使用。 自动生成的代码在源代码中需要一个明确的“#nullable”指令。

(强调添加到错误消息的新添加部分。)

因此,如果您在发出的任何 .generated.cs 文件中看到此错误消息,则需要在这些文件中添加 #nullable enable 明确 - Roslyn 显然总是忽略该项目 -生成代码的级别&lt;Nullable&gt;enable&lt;/Nullable&gt; 设置。

【讨论】:

C# 生成文件的可为空上下文的文档位于docs.microsoft.com/en-us/dotnet/csharp/… 下。他们添加了一个“重要”小节,列出了文件被标记为已生成的 4 种方式。 感谢您的链接,这是一个很好的发现!他们终于添加了文档,这很好。但很糟糕的是,这是几年前完全没有记录的“魔法”规则。 即使在新创建的 .NET 6.0 项目、自己的代码、不使用 C#8 可空引用类型的旧解决方案中,我也收到了 CS8632 警告。新项目设置了&lt;Nullable&gt;enable&lt;/Nullable&gt;。解决方案:删除解决方案中的所有binobj目录,同样建议MS迁移net6。在我的情况下,“清洁解决方案”是不够的。

以上是关于可空引用类型的注释只能在“#nullable”上下文中的代码中使用的主要内容,如果未能解决你的问题,请参考以下文章

引用类型与可空类型 ToString()

C# 可空值类型

kotlin 注释处理器中的可空类型

C# 8中的可空引用类型

可空类型产生警告,因为项目已启用可空引用类型

C#可空类型(Nullable)