是否可以通知 C# 编译器另一个 属性 将基于另一个 属性 为非空?
Is it possible to inform the C# compiler that another property will be non-null based on another property?
假设我有一个这样的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 提供空安全断言。
您可以查看 C# 9 和 .NET 5 中引入的 MemberNotNullWhen
属性,然后编写如下内容:
[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
假设我有一个这样的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 提供空安全断言。
您可以查看 C# 9 和 .NET 5 中引入的 MemberNotNullWhen
属性,然后编写如下内容:
[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