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

Can I tell C# nullable references that a method is effectively a null check on a field

考虑以下代码:

#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 表面的 public 部分。有很多理由想要将 null 检查纳入它自己的方法中,但这样做似乎会破坏可为 null 的引用检查器。

String是引用类型,nullable(例如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();
        }
    }
}

更新:

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# 9.0 中检查 [MemberNotNull(nameof(Property))][MemberNotNullWhen(true, nameof(Property))] 属性。

https://github.com/dotnet/runtime/issues/31877