可为空的引用类型和构造函数警告

Posted

技术标签:

【中文标题】可为空的引用类型和构造函数警告【英文标题】:Nullable reference types and constructor warnings 【发布时间】:2020-07-28 01:51:15 【问题描述】:

我正在尝试在我的项目中采用 C# 8 的可为空引用类型,并使其与 EF Core 顺利配合。

在this guide 之后,我使我的实体类具有构造函数,该构造函数接受初始化其不可为空属性所需的所有数据:

public class MyEntity
    
        public MyEntity(int someNumber, string name, string shortName, bool active)
        
            SomeNumber= someNumber;
            Name = name;
            ShortName = shortName;
            Active = active;
        

        public int SomeNumber  get; set; 
        public string Name  get; set; 
        public string ShortName  get; set; 
        public string? SomethingOptional  get; set; 
        public bool Active  get; set; 
    

在我的业务案例中,我有时需要更新实体的所有属性。我可以使用属性设置器,但由于我想通过加倍初始化语法来确保不会遗漏任何内容(实际上我的实体可以有 10 个或更多属性),为了方便起见,我决定创建一个公共 Update() 函数并调用它而不是构造函数体:

        public MyEntity(int someId, string name, string shortName, bool active)
        
            Update(someId, name, shortName, active);
        

        public void Update(int someId, string name, string shortName, bool active)
        
            SomeNumber = someId;
            Name = name;
            ShortName = shortName;
            Active = active;
        

现在,在创建实体时,我调用构造函数,在更改它时,我调用 Update()。 但是,现在编译器会给出可空性警告 (CS8618),即构造函数未初始化不可为空的属性。显然无法猜测调用 Update 会初始化它们。

我可能使用 Update() 方法对其进行了过度设计,但现在我很好奇 有没有办法让编译器相信我的构造函数会初始化属性? p>

【问题讨论】:

【参考方案1】:

确实有点冗长,但是你可以使用 .NET 5 中的[MemberNotNull] 属性告诉编译器一个方法确保一个成员返回后不为空。

using System.Diagnostics.CodeAnalysis;
    
public class MyEntity

    [MemberNotNull(nameof(Name), nameof(ShortName))]
    public void Update(int someId, string name, string shortName, bool active)
    
        SomeNumber = someId;
        Name = name;
        ShortName = shortName;
        Active = active;
    

【讨论】:

【参考方案2】:

如果你确定你在做什么,那么你可以通过

来抑制编译器警告
#pragma warning disable CS8618
public MyEntity(int someNumber, string name, string shortName, bool active)

    SomeNumber= someNumber;
    Name = name;
    ShortName = shortName;
    Active = active;

#pragma warning disable CS8618

还有一个开放的case for that in github,你可以查一下。您可以使用下面的方法(引用自github)

class MyClass

    private string m_str1;
    private string m_str2;

    public MyClass()
    
        Init(out m_str1, out m_str2);
    

    private void Init(out string str1, out string str2)
    
        str1 = string.Empty;
        str2 = string.Empty;
    

【讨论】:

以上是关于可为空的引用类型和构造函数警告的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 System.Text.Json 处理可为空的引用类型?

如何识别泛型类型的可为空引用类型?

C# 8.0 不可为空的引用类型和选项模式

在 C# 10.0 中启用了可为空的仅初始化引用属性

C#中的?和??的用法

C#中 ?? ? ?: ?.?[ ]