退出构造函数时,不可为空的属性必须包含非空值。考虑将属性声明为可为空

Viv*_*Dev 3 c# visual-studio

我有一个像这样的简单类。

public class Greeting
{
    public string From { get; set; }
    public string To { get; set; } 
    public string Message { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

奇怪的是,我收到以下警告。

Severity    Code    Description Project File    Line    Suppression State
Warning CS8618  Non-nullable property 'From' must contain a non-null value when exiting constructor. 
Consider declaring the property as nullable.    MxWork.Elsa2Wf.Tuts.BasicActivities  
D:\work\MxWork\Elsa2.0WfLearning\MxWork.Elsa2.0Wf.Tuts\src 
\MxWork.Elsa2Wf.Tuts.BasicActivities\Messages\Greeting.cs   5   Active
Run Code Online (Sandbox Code Playgroud)

我很困惑。它抛出的这些新信息打击了我的信心。我从所有三个属性中得到它们。而这突然出现了。

有人可以建议如何减轻这种情况。

视觉工作室警告消息

viv*_*una 195

如果您不想这样做,可以通过从 csproj 文件中删除以下行或将其设置为disable. 默认值为disable

<Nullable>enable</Nullable>
Run Code Online (Sandbox Code Playgroud)

是官方文档。

  • 这感觉更像是一个创可贴,而不是一个实际的解决方案。我认为 @slate 拥有最好的解决方案,对于较小的项目,我认为 Daryl Wagoner 的选择很棒,Vivek 后来建议直接将属性注释为不可为空。 (6认同)
  • 我认为考虑不禁用它可能是件好事……虽然这对现有项目来说有点痛苦,但它确实有助于空安全代码的概念。 (3认同)
  • 我已完全关闭 Visual Studio,编辑 csproj 文件以删除这些行,重新打开我的解决方案,但我仍然看到警告。 (2认同)
  • @RayGoudie 尝试清理并再次构建。您的解决方案中是否有多个项目?如果是,那么您必须从所有项目中删除该行。 (2认同)
  • 对我来说这似乎是一堆废话。接下来你知道,`public int Id { get; 放; }` 属性必须初始化为 `0` (2认同)

Yor*_*oro 65

C#11 (.NET 7.0 ) 开始,您可以添加required修饰符。

public class Greeting
{
    public required string From { get; set; }
    public required string To { get; set; } 
    public required string Message { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

此功能旨在改进我们初始化不依赖构造函数参数的对象的方式,这样就不会感觉像作弊。

但是使用required修饰符,您将无法使用它var greeting = new Greeting();来创建对象实例。现在创建一个对象实例必须执行以下操作:

var greeting = new Greeting()
{
   "Me",
   "You",
   "Some msg..",
};
Run Code Online (Sandbox Code Playgroud)

最初的答案发布于: What is best way to create .NET6 class with many non-nullable property?

更详细的信息: https ://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/required

  • 在使用自动创建的类(如 ASPNET 模型绑定、AutoMapper 等)时,请小心使用“required”。在这些情况下,带有“[required]”数据注释的“= null!”可能更有意义。 (2认同)

小智 54

您可以直接将属性注释为不可为空。

public string Property{ get; set; } = null!;
Run Code Online (Sandbox Code Playgroud)

Property如果用户尝试将其设置为,它会发出警告null

  • 如果你指定 `null!;`,你就是在对编译器说“分配这个 null,但是相信我,它不是 null”。请参阅 https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving (36认同)
  • 我认为这个答案对于在 EF Core 中使用导航属性很有用。我还注意到,在从数据库脚手架代码生成的 EF 核心计算机中,默认情况下不可为空的导航属性具有此属性。 (3认同)

Zac*_*ott 19

对于使用可为空引用类型的实体框架:

public class NullableReferenceTypesContext : DbContext {
    public DbSet<Customer> Customers => Set<Customer>();
    public DbSet<Order> Orders => Set<Order>();
}
Run Code Online (Sandbox Code Playgroud)


小智 18

You can also implement a constructor to remove the error.

public class Greeting
{
    public string From { get; set; }
    public string To { get; set; }
    public string Message { get; set; }

    public Greeting(string from, string to, string message)
    {
        From = from;
        To = to;
        Message = message;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个非常重要的方面:也许不在这个特定线程的问题中,但在某些情况下,属性*必须*按设计为非空。因此,在创建类实例时必须使用构造函数提供一个值。dotnet 中的默认设置强制处理此问题是有原因的。仅用“?”标记属性 (可空)当它们实际上*可以*为空时。因此,所有建议“关闭警告”的答案都是完全粗心的。 (4认同)

Dar*_*ner 15

在运行应用程序时,启用可空引用类型将为您省去很多麻烦。大量警告的问题在于,大多数警告可能不会引起问题,但它可能隐藏了导致难以发现的错误的警告。

使用它有一些问题,比如 Slate 和其他人指出的问题并回答得很好。

尽可能接近零警告是一个非常好的主意。

启用 nullable 后,它会产生很多警告。很多时候编译器只是知道某些东西可能为空。但是,您比编译器更聪明,您知道当它到达该代码时它不会为空。

例如:

    public partial class Exams: ComponentBase
    {
    [Inject] private IQuestionPoolFetchService? QPoolService { get; init; }


        private async Task FetchQuestionPool()
        {
            await QPoolService.GetAllQuestionsFromText();
        }
Run Code Online (Sandbox Code Playgroud)

这将引发 CS8602 警告。因为也许 DI 会以某种方式发送空值。当然,我们知道这不会发生。

您可以使用 #prama 消除警告,例如:

    public partial class Exams: ComponentBase
    {
    [Inject] private IQuestionPoolFetchService? QPoolService { get; init; }


        private async Task FetchQuestionPool()
        {
#pragma warning disables CS8602 // Dereference of a possibly null reference.
            await QPoolService.GetAllQuestionsFromText();
#pragma warning restore CS8602 // Dereference of a possibly null reference.
        }
Run Code Online (Sandbox Code Playgroud)

这是非常丑陋的代码,如果您必须重复多次,它会变得更糟。

更好的解决方案: 使用 null-forgiving 运算符。“!”

public partial class Exams: ComponentBase
{
[Inject] private IQuestionPoolFetchService? QPoolService { get; init; }


    private async Task FetchQuestionPool()
    {
        await QPoolService!.GetAllQuestionsFromText();
        // null-forgiving ^
    }
Run Code Online (Sandbox Code Playgroud)

这告诉编译器嘿,我知道这可能为空,但它不会。

  • 有没有办法将属性本身注释为非空?否则,像 Hot Chocolate (GraphQL) 这样使用反射的库就无法知道。 (2认同)

roh*_*095 10

单击项目名称 -> 打开 .csproj 文件

Replace <Nullable>enable</Nullable>

With <Nullable>disable</Nullable>
Run Code Online (Sandbox Code Playgroud)

  • 这确实不是一个好主意。dotnet 启用 nullable 作为默认值是有原因的 (2认同)

kjh*_*jhf 6

编译器警告您,您的字符串属性的默认分配(空值)与其声明的类型(非空值)不匹配string

当打开可为空的引用类型时会发出此消息,这会将所有引用类型更改为非空,除非使用?.

例如,您的代码可以更改为

public class Greeting
{
    public string? From { get; set; }
    public string? To { get; set; } 
    public string? Message { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

将属性声明为可为空的字符串,或者您可以在线或在构造函数中提供属性默认值:

public class Greeting
{
    public string From { get; set; } = "default from";
    public string To { get; set; } = "default to";
    public string Message { get; set; } = "default message";
}
Run Code Online (Sandbox Code Playgroud)

如果您希望将属性的类型保留为非空。

  • [后期初始化属性、数据传输对象和可为空性](https://learn.microsoft.com/en-us/dotnet/csharp/nullable-migration-strategies#late-initialized-properties-data-transfer-objects- and-nullability),介绍了在打开可空引用类型时进行迁移的 3 种策略:构造函数绑定、创建可空支持字段以及使用空宽恕运算符将属性初始化为空。 (6认同)
  • 格兰特链接的页面已更改,不再有该部分。它位于互联网档案馆中:[后期初始化的属性、数据传输对象和可为空性](http://web.archive.org/web/20210507001828/https://learn.microsoft.com/en-us/ dotnet/csharp/nullable-migration-strategies) (6认同)
  • 不可空字符串的合理默认值通常是“string.Empty”。 (2认同)
  • @variable 如果您的类型是非空“string”,那么如果您尝试为属性分配空值或可能为空值,包括您之前使用“null!”初始化它,您将会收到警告。如果在这种情况下您没有收到警告,请检查该文件是否可以为空,并且您的类型是否为非空。 (2认同)

小智 6

只需输入:

#nullable disable
Run Code Online (Sandbox Code Playgroud)

在 Razor 页面的顶部


Bea*_*eau 6

在 Visual Studio 2022 v17.2.3 Visual Studio 项目设置中

右键单击您的项目标题 > 属性 > 应用程序 > 打包 > 在“构建”部分下 > 在下拉列表中设置“Nullable”=“启用”。