如何让 C# 意识到方便属性的可空性?

How to make C# aware of the nullability of convenient properties?

考虑这个代码片段,它没有可为 null 的警告。

public class Foo {
    public string Property { get; } = "Some String";
}

public class Bar {
    [DisallowNull]
    public Foo? Foo { get; private set; }
    
    [MemberNotNull(nameof(Foo))]
    public void MyMethod() {
        Foo = new Foo();
        
        // After setting Foo, I use Foo.Property in some way
        Console.WriteLine(Foo.Property);
    }
}

由于在我的真实代码中,我在设置Foo 后使用Foo.Property很多,我想添加一个“方便属性 " 到 Bar 直接 returns 它,这样我就可以使用更短的名称访问它(Foo 在我的真实代码中实际上是一个相当长的名称):

// in Bar
public string? Property => Foo?.Property;

// ...
// Now I can do:
Console.WriteLine(Property);

但是,现在Bar.Property是可以为空的,即使在Foo肯定不为空的地方(比如刚刚设置Foo之后)。因此,当我在不允许使用 null 的地方使用 Property 时,编译器会给我警告。

我以为我需要的是用NotNullIfMemberNotNull(nameof(Foo))之类的东西来注释Property,但是在查找之后,this attribute is only proposed, and doesn't exist yet

我该如何解决这个问题?

我想出的一个解决方法是让 FooProperty 都有支持字段。在Foo的setter中,也设置Property。这样,我们就可以在Foo的setter中添加MemberNotNull属性了。

private Foo? foo;

[DisallowNull]
public Foo? Foo { 
    get => foo;
    [MemberNotNull(nameof(Property))]
    private set {
        foo = value;
        Property = value.Property;
    }
}

public string? Property { get; private set; }

然而,这不是很普遍。它之所以有效,是因为 Foo 恰好被标记为 DisallowNull.

首先,MemberNotNull 是一个 post 条件,它仅向调用者发出信号,表明指定成员在成员 returns 之后不会为 null。不幸的是,它不会在方法本身内帮助您。

我知道你正在使用一个更大模式的简化,但我建议重写 MyMethod 的一种方法是:

public void MyMethod() {
    var foo = new Foo();
    Foo = foo;
    Console.WriteLine(foo.Property);
}