在WPF RelayCommand中处理CS8602的常用方法是什么?

问题描述 投票:0回答:1
如果在 RelayCommand 的

Execute

 部分中使用了可为 null 的属性,并且该属性已在 
CanExecute
 方法中针对 null 进行了检查,那么处理该属性的 
CS8602: Possible dereference of null
 警告的正确方法是什么?

[ObservableProperty, NotifyCanExecuteChangedFor(nameof(FooCommand)] private FooType? _fooObject; [RelayCommand(CanExecute = nameof(CanExecuteFooCommand)] private void Foo() { SomeMethod(FooObject.ID); // gives CS8602: Possible dereference of null } private bool CanExecuteFooCommand() { return FooObject is not null; } private void SomeMethod(Guid? fooObject) { }
您认为哪种方式是正确的?

FooObject

 中的 
Execute
 进行另一个空检查?

?

 中使用可空类型 
SomeMethod(FooObject?.ID)

!

 中使用 null 宽容运算符 
SomeMethod(FooObject!.ID)

或者还有其他我不知道的方法吗?

FooObject

 是否可以在 
CanExecute
Execute
 部分之间变为空?

c# wpf nullable community-toolkit-mvvm
1个回答
0
投票
代码

CS8602只是来自静态分析器的警告。它不会从语义上分析您的代码。它不知道该变量永远不会为空 - 至少在代码或执行路径的这一点上。您将变量 FooObject

 标记为可为空,因此分析器会显示警告 
“可能取消引用 null”

您可以使用 null-forgiving 运算符

!

 告诉分析器您已意识到风险,但要知道,虽然理论上是可能的,但此时该值永远不会是 
null

请注意,零容忍运算符只会使分析器静音。如果您重构代码,例如更改流程,现在允许变量为

null

,那么您的代码将会抛出异常。因此,在未来的代码更改后,始终存在变量永远不会 
null
 的保证变得无效的风险。我认为出于这个原因,应该谨慎或谨慎地使用它,因为分析器可空检查可能非常有帮助。

我想大多数时候使用编译器检查来满足分析器的要求会增加必要的稳健性。例如,模式匹配就是一个很好的方法。有很多方法可以检查

null

抛出
ArgumentNullException
 异常也是一种增加鲁棒性的选项,因为这可以防止 
null
 参数值(并且也满足分析器的要求)。

“在 CanExecute 和 Execute 部分之间 FooObject 是否会变为 null?”

如果您可以保证

ICommand.CanExecute

 始终在 
ICommand.Execute
 之前直接调用(WPF 
ICommandSource
 实现就是这种情况,如 
Button
 和成员变量),那么您的 
Execute
 实现引用不会在之间共享线程,那么在这种情况下您可以安全地使用 null-forgiving 运算符,否则,我将显式执行编译器检查。

private FooType? _fooObject; private void Foo() { // To add robustness, especially in anticipation of future changes, // you probably want to let the compiler check the property // e.g. by using pattern matching if (_fooObject is not null) { SomeMethod(_fooObject.ID); } } // Guid is a struct. As such, it can NEVER be NULL! // The NULL value would be implicitly converted to default(Guid) // However, when you make it nullable you must check the parameter to avoid bugs private void SomeMethod(Guid? fooObject) { if (fooObject == Guid.Empty || fooObject == default) { return; } }
    
© www.soinside.com 2019 - 2024. All rights reserved.