c# - 是否可以根据另一个属性通知 C# 编译器另一个属性将是非空的?

标签 c# nullable c#-8.0 nullable-reference-types c#-9.0

假设我有这样的类(class):

public class BridgeFormModel
{
    [Required]
    [Display( Name = "What is your name?" )]
    public String? Name { get; set; }

    [Required]
    [Display( Name = "What is your quest?" )]
    public String? Quest { get; set; }

    [Required]
    [Display( Name = "What is your favourite colour?" )]
    public String? FaveColour { get; set; }

    [BindNever]
    public Boolean IsValid =>
        !String.IsNullOrWhiteSpace( this.Name ) && 
        !String.IsNullOrWhiteSpace( this.Quest ) && 
        !String.IsNullOrWhiteSpace( this.FaveColour );
}

当前 C# 8.0 和 C# 9.0 编译器在知道 IsValid 为真时不会推断 Name 不为空:

public IActionResult CrossTheBridge( BridgeFormModel form )
{
    if( form.IsValid )
    {
        if( form.FaveColour.Equals( "Blue" ) ) // Warning: `form.FaveColour` may be null here
        {
            Console.WriteLine( "Right, off you go" )
        }
    }
}

所以我们必须要么断言 form.FaveColour! - 要么这样做:

public IActionResult CrossTheBridge( BridgeFormModel form )
{
    if( form.IsValid && form.FaveColour != null && form.Name != null && form.Quest != null )
    {
        if( form.FaveColour.Equals( "Blue" ) )
        {
            Console.WriteLine( "Right, off you go" )
        }
    }
}

我们有 [NullWhen][NotNullWhen] 属性,但它们仅适用于方法参数,不适用于同一对象实例上的其他属性。

如果 C# 仍然支持代码契约,这将不是问题,但是,唉,我们在这里......有没有办法根据属性通知 C# 编译器可空性(和其他状态不变量?) ?

我希望能够做这样的事情:

public class BridgeFormModel
{
    [NotNullWhenPropertyIsTrue( nameof(IsValid) )]
    [Required]
    [Display( Name = "What is your name?" )]
    public String? Name { get; set; }

    [NotNullWhenPropertyIsTrue( nameof(IsValid) )]
    [Required]
    [Display( Name = "What is your quest?" )]
    public String? Quest { get; set; }

    [NotNullWhenPropertyIsTrue( nameof(IsValid) )]
    [Required]
    [Display( Name = "What is your favourite colour?" )]
    public String? FaveColour { get; set; }

    [BindNever]
    public Boolean IsValid =>
        !String.IsNullOrWhiteSpace( this.Name ) && 
        !String.IsNullOrWhiteSpace( this.Quest ) && 
        !String.IsNullOrWhiteSpace( this.FaveColour );
}

由于 NotNullWhenPropertyIsTrue 不是真正的属性,我想知道是否有某种方法可以编写 Roslyn 扩展或分析器来实现必要的逻辑 - 或向 Roslyn 提供空安全断言。

最佳答案

你可以看看MemberNotNullWhen属性,它是在 C# 9 和 .NET 5 中引入的,并编写如下内容:

[MemberNotNullWhen(true, nameof(Name), nameof(Quest), nameof(FaveColour))]
public Boolean IsValid =>
        !String.IsNullOrWhiteSpace( this.Name ) && 
        !String.IsNullOrWhiteSpace( this.Quest ) && 
        !String.IsNullOrWhiteSpace( this.FaveColour );

设计说明和其他详细信息可在 dotnet 运行时 issue #31877 中找到

关于c# - 是否可以根据另一个属性通知 C# 编译器另一个属性将是非空的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66726837/

相关文章:

c# - 适用于 Windows Phone 8 的 OCR API

laravel - Illuminate\Database\QueryException SQLSTATE [23000] : Integrity constraint violation: 19 NOT NULL constraint failed

c# - C# 8 中的范围和索引类型是什么?

c# - EF Core 3.0 可为空的导航属性

c# - Assembly.GetManifestResourceStream(name) 是否在每次调用时返回一个新流?

c# - 有没有办法调整带有循环的表单上每个控件的字体大小?

c# - 如何捕捉异常

c# - 如何使绑定(bind)到 Nullable<int> 属性的 DropDownListFor 接受空值?

c# - 用BinaryWriter写入Nullable值

c# - "DoesNotReturn"属性的编译器错误