You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让C#识别非可空成员变量已完成初始化?

问题描述

我已经完成了所有非可空成员变量的初始化,但C#编译器无法识别,抛出CS8618警告。除了使用_elevatorPitch = default!;或#pragma warning disable CS8618之外,有没有其他方法消除这些警告?我希望保留警告功能,避免漏掉真正未正确初始化的情况,而且本次所有变量确实都完成了初始化。

相关代码

public CreateAppointmentDto(Event src, AppUser user, IBlobService blobService,
    IDocumentService documentService, IHttpClientFactory httpClientFactory, IEnumerable<Interest> allInterests)
{

    AllInterests = allInterests;

    ApplyFromEvent(src, user, blobService);
}

public void ApplyFromEvent(Event src, AppUser user, IBlobService blobService)
{

    ArgumentNullException.ThrowIfNull(src.Owner);
    ArgumentNullException.ThrowIfNull(src.Parent);
    ArgumentNullException.ThrowIfNull(src.Signups);
    if (src.AppointmentType == ExAppointmentType.OccurrenceInstance)
        throw new ArgumentException("Cannot edit an appointment that is an occurrence instance.");

    Event = src;
    Type = src.Type;
    _subject = src.Subject;
    _elevatorPitch = src.ElevatorPitch ?? string.Empty;
    HasAddress = src.HasAddress;
    AddressModel = new AddressFormPageModel(src.Address);
    Workplace = src.Workplace;
    Priority = src.Priority;
    MaxSignups = src.MaxSignups;
    Enabled = src.Enabled;
    Private = src.Private;

    Owner = src.Owner;
    ParentId = src.Parent.Id;
    Interest = src.Interest;
    Tags = src.Tags ?? new List<Tag>();

    // bugbug DescriptionRichText!.RichText = src.Description;
    Thumbnail = new FileUploadModel(blobService, src.Thumbnail, SystemBlobs.EventUploadThumbnail);
    Picture = new FileUploadModel(blobService, src.Picture, SystemBlobs.EventUploadPicture);

    StartDateTime = src.StartDateTime.DateTime;
    EndDateTime = src.EndDateTime.DateTime;
    TimeZoneId = src.StartDateTime.TimeZoneId;

    var signup = src.Signups.FirstOrDefault(s => s.User.Id == user.Id);
    StatusId = (int)(signup?.Commitment ?? Signup.Mode.Unknown);

    AppointmentType = (AppointmentType)(int)src.AppointmentType;
    AllDay = src.ApptAllDay;
    RecurrenceInfo = src.RecurrenceInfo;
    Shifts = src.ApptShifts != null ? ShiftItemModel.FromShiftList(src.ApptShifts) : new List<ShiftItemModel>();
}

警告信息

2>C:\Git\LouisHowe\LouisHowe.web\PageModels\EventJob\CreateAppointmentDto.cs(276,10,276,30): warning CS8618: Non-nullable field '_subject' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
2>C:\Git\LouisHowe\LouisHowe.web\PageModels\EventJob\CreateAppointmentDto.cs(276,10,276,30): warning CS8618: Non-nullable field '_elevatorPitch' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
2>C:\Git\LouisHowe\LouisHowe.web\PageModels\EventJob\CreateAppointmentDto.cs(276,10,276,30): warning CS8618: Non-nullable property 'TimeZoneId' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
2>C:\Git\LouisHowe\LouisHowe.web\PageModels\EventJob\CreateAppointmentDto.cs(276,10,276,30): warning CS8618: Non-nullable property 'AddressModel' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
2>C:\Git\LouisHowe\LouisHowe.web\PageModels\EventJob\CreateAppointmentDto.cs(276,10,276,30): warning CS8618: Non-nullable property 'Tags' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
2>C:\Git\LouisHowe\LouisHowe.web\PageModels\EventJob\CreateAppointmentDto.cs(276,10,276,30): warning CS8618: Non-nullable property 'Thumbnail' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
2>C:\Git\LouisHowe\LouisHowe.web\PageModels\EventJob\CreateAppointmentDto.cs(276,10,276,30): warning CS8618: Non-nullable property 'Picture' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
2>C:\Git\LouisHowe\LouisHowe.web\PageModels\EventJob\CreateAppointmentDto.cs(276,10,276,30): warning CS8618: Non-nullable property 'Shifts' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
解决方案

1. 使用MemberNotNull属性标注初始化方法(推荐)

C# 8.0及以上版本支持[MemberNotNull]属性,它能直接告诉编译器:调用指定方法后,列出的成员一定会被初始化。这种方法无需改动现有代码结构,同时保留警告的检测能力。

步骤:

  • 引用System.Diagnostics.CodeAnalysis命名空间
  • 在ApplyFromEvent方法上添加[MemberNotNull]属性,列出所有被初始化的非空成员

示例代码:

using System.Diagnostics.CodeAnalysis;

public CreateAppointmentDto(Event src, AppUser user, IBlobService blobService,
    IDocumentService documentService, IHttpClientFactory httpClientFactory, IEnumerable<Interest> allInterests)
{
    AllInterests = allInterests;
    ApplyFromEvent(src, user, blobService);
}

[MemberNotNull(nameof(_subject), nameof(_elevatorPitch), nameof(TimeZoneId), nameof(AddressModel), 
               nameof(Tags), nameof(Thumbnail), nameof(Picture), nameof(Shifts))]
public void ApplyFromEvent(Event src, AppUser user, IBlobService blobService)
{
    // 原初始化逻辑保持不变
}

2. 将初始化逻辑内联到构造函数

C#的静态分析无法追踪跨方法的初始化操作,把ApplyFromEvent里的代码直接移到构造函数内部,编译器就能识别到所有成员都已完成初始化。

示例代码:

public CreateAppointmentDto(Event src, AppUser user, IBlobService blobService,
    IDocumentService documentService, IHttpClientFactory httpClientFactory, IEnumerable<Interest> allInterests)
{
    AllInterests = allInterests;

    ArgumentNullException.ThrowIfNull(src.Owner);
    ArgumentNullException.ThrowIfNull(src.Parent);
    ArgumentNullException.ThrowIfNull(src.Signups);
    if (src.AppointmentType == ExAppointmentType.OccurrenceInstance)
        throw new ArgumentException("Cannot edit an appointment that is an occurrence instance.");

    Event = src;
    Type = src.Type;
    _subject = src.Subject;
    _elevatorPitch = src.ElevatorPitch ?? string.Empty;
    HasAddress = src.HasAddress;
    AddressModel = new AddressFormPageModel(src.Address);
    Workplace = src.Workplace;
    Priority = src.Priority;
    MaxSignups = src.MaxSignups;
    Enabled = src.Enabled;
    Private = src.Private;

    Owner = src.Owner;
    ParentId = src.Parent.Id;
    Interest = src.Interest;
    Tags = src.Tags ?? new List<Tag>();

    Thumbnail = new FileUploadModel(blobService, src.Thumbnail, SystemBlobs.EventUploadThumbnail);
    Picture = new FileUploadModel(blobService, src.Picture, SystemBlobs.EventUploadPicture);

    StartDateTime = src.StartDateTime.DateTime;
    EndDateTime = src.EndDateTime.DateTime;
    TimeZoneId = src.StartDateTime.TimeZoneId;

    var signup = src.Signups.FirstOrDefault(s => s.User.Id == user.Id);
    StatusId = (int)(signup?.Commitment ?? Signup.Mode.Unknown);

    AppointmentType = (AppointmentType)(int)src.AppointmentType;
    AllDay = src.ApptAllDay;
    RecurrenceInfo = src.RecurrenceInfo;
    Shifts = src.ApptShifts != null ? ShiftItemModel.FromShiftList(src.ApptShifts) : new List<ShiftItemModel>();
}

3. 确保依赖的源对象成员非空

检查src.Subject、src.StartDateTime.TimeZoneId等被赋值的成员是否本身标记为非可空。如果这些成员是可空类型,即使在方法内赋值,编译器仍会认为存在null风险。可以在ApplyFromEvent开头添加非空检查:

public void ApplyFromEvent(Event src, AppUser user, IBlobService blobService)
{
    ArgumentNullException.ThrowIfNull(src.Owner);
    ArgumentNullException.ThrowIfNull(src.Parent);
    ArgumentNullException.ThrowIfNull(src.Signups);
    ArgumentNullException.ThrowIfNull(src.Subject); // 添加该检查
    ArgumentNullException.ThrowIfNull(src.StartDateTime.TimeZoneId); // 添加该检查

    if (src.AppointmentType == ExAppointmentType.OccurrenceInstance)
        throw new ArgumentException("Cannot edit an appointment that is an occurrence instance.");

    // 剩余初始化逻辑不变
}

内容的提问来源于stack exchange,提问作者David Thielen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 22:34:56