我可以告诉C#可为空的引用方法实际上是对字段的空检查吗

Joh*_*lle 11 c# nullable-reference-types

考虑以下代码:

#nullable enable
class Foo
{
    public string? Name { get; set; }
    public bool HasName => Name != null;
    public void NameToUpperCase()
    {
        if (HasName)
        {
            Name = Name.ToUpper();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在Name = Name.ToUpper()上,我收到一条警告,指出Name是可能的空引用,这显然是错误的。我可以通过内联HasName来解决此警告,因此条件是if(Name!= null)。

有什么方法可以指示编译器,HasName的真实响应暗含对Name的不可为空性的约束?

这很重要,因为HasName实际上可能会测试更多的东西,并且我可能想在多个地方使用它,或者它可能是API表面的公共部分。有很多原因希望将空检查纳入其自己的方法中,但是这样做似乎破坏了可空引用检查器。

V0l*_*dek 7

更新:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

还有用于无条件断言的MemberNotNullAttribute

旧答案:

我环顾四周,System.Diagnostics.CodeAnalysis找不到任何适用的属性,这非常令人失望。你能得到的最接近你想要的东西似乎是:

#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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这看起来很麻烦,我知道。您可以查看可空属性的 MSDN 文档,也许您会发现更简洁的内容。

  • 我解决了“找不到此提案”的问题。(https://github.com/dotnet/csharplang/issues/2997)祝我好运。 (3认同)
  • 似乎我们需要更多属性或类似打字稿的断言之类的东西 (2认同)
  • @XIU编译器在这方面已经很宽松了。如果您执行“if(Name != null) return Null.ToUpper()”,则不会出现有关 null 取消引用的警告,即使从技术上讲这是一个 TOCTOU 竞争条件。我记得 Mads Torgersen 谈到了他们的想法,但它会产生如此多的误报,整个可空引用类型功能实际上毫无用处 - 99% 的时间你的属性不会被另一个线程更改。因此,您需要做的就是创建一个属性,使对此属性的检查被视为对另一个属性的 null 检查。 (2认同)