我可以告诉 C# 可空引用方法实际上是对字段的空检查吗
Posted
技术标签:
【中文标题】我可以告诉 C# 可空引用方法实际上是对字段的空检查吗【英文标题】:Can I tell C# nullable references that a method is effectively a null check on a field 【发布时间】:2020-03-19 23:07:53 【问题描述】:考虑以下代码:
#nullable enable
class Foo
public string? Name get; set;
public bool HasName => Name != null;
public void NameToUpperCase()
if (HasName)
Name = Name.ToUpper();
在 Name=Name.ToUpper() 上,我收到一条警告,指出 Name 可能是空引用,这显然是不正确的。我可以通过内联 HasName 来解决此警告,因此条件是 if (Name != null)。
有什么方法可以指示编译器 HasName 的真实响应意味着对 Name 的不可为空性约束?
这很重要,因为 HasName 实际上可能会测试更多的东西,我可能想在多个地方使用它,或者它可能是 API 表面的公共部分。有很多理由希望将 null 检查因素考虑到它自己的方法中,但这样做似乎会破坏可空引用检查器。
【问题讨论】:
IMO 你应该在可空类型上使用HasValue
,而不是对照null
。不过,它可能不会影响您的问题。
我认为对于您的情况,您可以使用#nullable disable
包装您的代码,然后再使用#nullable enable
或restore
(docs.microsoft.com/en-us/dotnet/csharp/…)。
您可以使用“该死”!
运算符。 if(HasName) Name = Name!.ToUpper();
对于多线程应用程序,您可以在 HasName 检查后让 Name 为 null,在本地使用变量而不是返回到属性(谁知道该属性在其 getter 中可能会做什么)是会给出一些时髦的错误(请记住使用事件处理程序,这种情况经常发生)
【参考方案1】:
更新:
C# 9.0 以MemberNotNullWhenAttribute 的形式引入了您要查找的内容。在您的情况下,您想要:
#nullable enable
class Foo
public string? Name get; set;
[MemberNotNullWhen(true, nameof(Name))]
public bool HasName => Name != null;
public void NameToUpperCase()
if (HasName)
Name = Name.ToUpper();
还有MemberNotNullAttribute 用于无条件断言。
旧答案:
我环顾了System.Diagnostics.CodeAnalysis
的不同属性,找不到任何适用的东西,这非常令人失望。最接近您想要的似乎是:
public bool TryGetName([NotNullWhen(true)] out string? name)
name = Name;
return name != null;
public void NameToUpperCase()
if (TryGetName(out var name))
Name = name.ToUpper();
我知道,它看起来很麻烦。你可以看看the MSDN docs for nullable attributes,说不定你会发现更整洁的东西。
【讨论】:
似乎我们需要更多属性或类似打字稿的断言 我会选择这个作为答案,因为我担心的真正答案似乎是“不,c# 还没有这样做。” @JohnMelville 我也找不到此类功能的提案,所以我认为我们不会很快期待这种变化。 @XIU 编译器在这方面已经松懈了。如果您执行if(Name != null) return Null.ToUpper()
,则不会出现空取消引用的警告,即使从技术上讲它是一个 TOCTOU 竞争条件。我记得 Mads Torgersen 谈到他们是如何考虑这一点的,但它会产生如此多的误报,整个可空引用类型功能实际上将毫无用处 - 99% 的时间你的属性不会被另一个线程更改。因此,您需要做的就是创建一个属性,使对该属性的检查被视为对另一个属性的 null 检查。
我修复了“找不到这个建议”的问题。 (github.com/dotnet/csharplang/issues/2997) 祝我好运。【参考方案2】:
在 C# 9.0 中检查 [MemberNotNull(nameof(Property))]
和 [MemberNotNullWhen(true, nameof(Property))]
属性。
https://github.com/dotnet/runtime/issues/31877
【讨论】:
【参考方案3】:String 是引用类型,可为 null(例如 int?
)是可为 null 的值类型。所以你真的不能这样做string? myString
;你需要的是这样的:
class Foo
public string Name get; set;
public bool HasName => !String.IsNullOrEmpty(Name); ////assume you want empty to be treated same way as null
public void NameToUpperCase()
if (HasName)
Name = Name.ToUpper();
【讨论】:
你已经过时了docs.microsoft.com/en-us/dotnet/csharp/language-reference/… @AluanHaddad 我相信你的意思是发送这个而不是docs.microsoft.com/en-us/dotnet/csharp/nullable-references以上是关于我可以告诉 C# 可空引用方法实际上是对字段的空检查吗的主要内容,如果未能解决你的问题,请参考以下文章
可空引用类型意外 CS8629 可空值类型可能为带有临时变量的空