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

我有一个这样的简单类。

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

我感到很困惑,这些新的信息打击了我的信心。 我从三处房产中都找到了。 这个突然出现了。

能不能有人建议如何减轻这种情况。

visual studio warning message

更新

这些天,我已经看到使用 默认!喜欢这样,它的工作。

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; };
}
106984 次浏览

编译器警告您,字符串属性的默认赋值(为 null)与其指定的类型(非 null string)不匹配。

这在 可为空的引用类型打开时发出,将所有引用类型更改为非空,除非 ?另有说明。

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

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;
}

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

在运行应用程序时,打开可空引用类型将为您节省很多麻烦。大量警告的问题在于,大多数警告可能不会导致问题,但它可能会隐藏那个导致难以找到的 bug 的警告。

有一些陷阱在使用它像问题指出,并回答了很好的 Slate 和其他人。

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

如果启用了 nullable,则会产生大量警告。很多时候,编译器只知道某些内容可能为空。但是,你比编译器聪明,你知道当它到达那个代码的时候,它不会是空的。

例如:

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




private async Task FetchQuestionPool()
{
await QPoolService.GetAllQuestionsFromText();
}

这将抛出一个 CS8602警告。因为也许督察会发送一个空值。当然,我们知道这是不可能的。

你可以用 # 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 ^
}

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

如果您不希望这样,您可以通过删除 csproj 文件中的下面一行或将其设置为 disable来禁用它。默认值为 disable

<Nullable>enable</Nullable>

这里 是官方文件。

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

public string Property{ get; set; } = null!;

如果用户试图将 Property设置为 null,它将给出警告

还可以实现构造函数来删除错误。

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;
}
}

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

public class NullableReferenceTypesContext : DbContext {
public DbSet<Customer> Customers => Set<Customer>();
public DbSet<Order> Orders => Set<Order>();
}

当我搜索这个问题,特别是 Blazor WebAssembly [ WASM ]时,我找到了 Darryl Wagoner WA1gon的替代答案。

使用 [DisallowNull],这是一个根据微软的文档 由 C # 编译器解释的空状态静态分析的属性先决条件后卫。值得更深入地阅读。

public partial class UploadView : FluxorComponent
{
private static readonly Serilog.ILogger logger = Serilog.Log.ForContext<UploadView>();


[Parameter][DisallowNull] public string? UploadHeader { get; set; }
[Parameter][DisallowNull] public EventCallback<SaveFile>? OnUploaded { get; set; }


[Inject][DisallowNull] private IState<UploadViewState>? State { get; set; }
[Inject][DisallowNull] private IDispatcher? Dispatcher { get; set; }


// NOTE: I included this as an example of trying to use the null-forgiveness / old school approach
public UploadViewState Model {
get {
if (State is null) { logger.Warning("{@Component}.Model - State is null", GetType().Name); }
if (State?.Value is null) { logger.Warning("{@Component}.Model - State.Value is null", GetType().Name); }


return State!.Value!;
}
}


protected override void OnInitialized()
{
base.OnInitialized();


Dispatcher.Dispatch(new Initialized());
Dispatcher.Dispatch(new UploadFileSizeChanged(524288000));


logger.Debug("{@Component} - Initialized", GetType().Name);
}


// yada yada...
}

注意: 如果这看起来像是你需要维护的大量工作,你可以使用这个 福迪 · 韦弗来为你完成它。

就写:

#nullable disable

在剃刀页的顶部

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

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

单击 ProjectName-> Open. csproj 文件

Replace <Nullable>enable</Nullable>


With <Nullable>disable</Nullable>

如果您使用的是一个实体框架,您的 nullable/non-nullable 属性应该与您的数据库对齐,这将是 NULL 或 NOT NULL; 无论是 SQL,json,等等。这只是我的个人观点,但我更喜欢在构建级别保持一致性,而不是发出某些警告。换句话说,如果数据库中的数据是非空的,那么用于导入该数据的代码的数据结构也应该是非空的,反之亦然。

当使用 String列表时,您可以使用:

public List<string> ? nameOfPublicConstructor { get; set; }