退出构造函数时,不可为空的属性必须包含非空值。考虑将属性声明为可为空
Posted
技术标签:
【中文标题】退出构造函数时,不可为空的属性必须包含非空值。考虑将属性声明为可为空【英文标题】:Non-nullable property must contain a non-null value when exiting constructor. Consider declaring the property as nullable 【发布时间】:2021-08-02 22:01:18 【问题描述】:我有一个像这样的简单课程。
public class Greeting
public string From get; set;
public string To get; set;
public string Message get; set;
奇怪的是,我收到以下警告。
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
我很困惑。它抛出的这些新类型的信息降低了我的信心。 我从所有三个属性中得到它们。 而这突然出现了。
有人可以建议如何减轻这种情况。
更新
这些天我看到像这样使用 default! 并且它的工作原理。
public class Greeting
public string From get; set; = default!;
public string To get; set; = default!;
public string Message get; set; = default!;
如果你觉得合适的话,你也可以放一个问号(?)来表示该类型是可以为空的。
public class Greeting
public string? From get; set; ;
public string? To get; set; ;
public string? Message get; set; ;
【问题讨论】:
您已启用Nullable Reference Types。如果您没有预料到这一点,并且您不确定如何使用它们,最好将它们关闭(直到您有机会跟上进度) 这正是为了增加您对代码的信心而发出警告。没有它,以后更容易出现空引用错误。 关于您的更新,对于字符串和其他引用类型,default!
与 null!
相同。我更喜欢null!
,因为使用default
不会添加任何有用的信息,并且会误导人们认为null
之外的其他内容被设置在那里。
【参考方案1】:
如果您不想这样做,可以通过从 csproj 文件中删除以下行或将其设置为 disable
来禁用此功能。默认值为disable
。
<Nullable>enable</Nullable>
Here是官方文档。
【讨论】:
解决问题太好了 我已完全关闭 Visual Studio,编辑我的 csproj 文件以删除这些行,重新打开我的解决方案,但我仍然看到警告。 @RayGoudie 尝试清理并再次构建。您的解决方案中是否还有多个项目?如果是,那么您必须从所有项目中删除该行。 只有一个项目。清理和重建,以及删除 obj 目录并没有删除警告。 这感觉更像是一种创可贴,而不是真正的解决方案。我认为@slate 有最好的解决方案,对于较小的项目,我认为 Daryl Wagoner 的选择以及 Vivek 后来直接将属性注释为不可为空的建议都很棒。【参考方案2】:编译器警告您,字符串属性的默认分配(为 null)与其声明的类型(非 null string
)不匹配。
当nullable reference types 被打开时发出,这会将所有引用类型更改为非空,除非用?
另有说明。
例如,您的代码可以更改为
public class Greeting
public string? From get; set;
public string? To get; set;
public string? Message get; set;
将属性声明为可为空的字符串,或者您可以在线或在构造函数中提供属性默认值:
public class Greeting
public string From get; set; = string.Empty;
public string To get; set; = string.Empty;
public string Message get; set; = string.Empty;
如果您希望将属性的类型保留为非空。
【讨论】:
不可为空字符串的合理默认值通常是string.Empty
。
Late-initialized properties, Data Transfer Objects, and nullability,介绍了在可空引用类型打开时迁移的 3 种策略、构造函数绑定、创建可空支持字段以及使用空宽恕运算符将属性初始化为空。跨度>
Grant 链接的页面已更改,不再包含该部分。它在 Internet 档案中:Late-initialized properties, Data Transfer Objects, and nullability
但不是字符串string test;
默认测试为空
@variable 正确,如果您启用了 Nullable,则不允许这样做。【参考方案3】:
您可以将属性直接注释为不可为空。
public string Property get; set; = null!;
如果用户尝试将Property
设置为null
,它会发出警告
【讨论】:
我没有收到警告是我尝试将属性设置为空。 如果您指定null!;
,您是在对编译器说“分配这个空值,但相信我,它不是空值”。见docs.microsoft.com/en-us/dotnet/csharp/language-reference/…【参考方案4】:
在运行应用程序时,启用可为空的引用类型将为您省去很多麻烦。许多警告的问题在于,大多数警告可能不会导致问题,但它可能会隐藏导致难以发现的错误的警告。
使用它有一些陷阱,就像问题指出的那样,Slate 和其他人回答得很好。
让警告尽可能接近于零是一个非常好的主意。
启用 nullable 后,它会产生很多警告。很多时候,编译器只知道某些东西可能为空。但是,您比编译器更聪明,您知道当它到达该代码时它不会为空。
例如:
public partial class Exams: ComponentBase
[Inject] private IQuestionPoolFetchService? QPoolService get; init;
private async Task FetchQuestionPool()
await QPoolService.GetAllQuestionsFromText();
这将引发 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.
这是非常难看的代码,如果你必须重复多次,就会变得更糟。
更好的解决方案: 使用容错运算符。 “!”
public partial class Exams: ComponentBase
[Inject] private IQuestionPoolFetchService? QPoolService get; init;
private async Task FetchQuestionPool()
await QPoolService!.GetAllQuestionsFromText();
// null-forgiving ^
这告诉编译器嘿,我知道这可能为空,但它不会。
【讨论】:
有没有办法将属性本身注释为非空?否则,像 Hot Chocolate (GraphQL) 这样使用反射的库是无法知道的。【参考方案5】:您还可以实现构造函数来消除错误。
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;
【讨论】:
【参考方案6】:对于实体框架Working with nullable reference types:
public class NullableReferenceTypesContext : DbContext
public DbSet<Customer> Customers => Set<Customer>();
public DbSet<Order> Orders => Set<Order>();
【讨论】:
以上是关于退出构造函数时,不可为空的属性必须包含非空值。考虑将属性声明为可为空的主要内容,如果未能解决你的问题,请参考以下文章