【问题标题】:How to make C# aware of the nullability of convenient properties?如何让 C# 意识到便利属性的可空性?
【发布时间】:2021-08-02 10:04:17
【问题描述】:

考虑一下这段代码 sn-p,它没有可以为空的警告。

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 中添加一个“方便属性”直接返回它,这样我可以使用较短的名称访问它(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

我该如何解决这个问题?

【问题讨论】:

  • 当你说“方便的属性”时,你的意思是“自动实现的属性”吗?
  • @Llama 不,我的意思是一个只返回另一个属性的属性的属性,就像Bar 中的Property 如何返回Foo.Property。基本上是为了缩短名字,这样我就不用每次都写Foo.了。
  • 关于 foo - 为什么你允许 null (foo?) 但用 [DisallowNull] 装饰它。不应该是[DisallowNull] public Foo foo { get; private set; } 吗? (没有“Elvis”运算符)同样与您的财产public string? Property - 为什么在这里使用? 运算符?
  • @Matt 因为它没有在构造函数中初始化(在我的用例中这样做没有意义),但不应将 null 分配给它。本质上,这里的Foodocumentation 中描述的ReviewComment 的示例非常相似。
  • 我明白了 - 所以你让它可以为 null 以表明它没有被正确初始化,但你一般想禁止 null。

标签: c# nullable-reference-types


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    首先,MemberNotNull 是一个后置条件,它只向调用者发出信号,表明指定的成员在成员返回后不会为空。不幸的是,它对方法本身没有帮助。

    我了解您正在使用更大模式的简化,但我建议重写 MyMethod 的一种方法是:

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

    【讨论】:

      猜你喜欢
      • 2015-05-19
      • 1970-01-01
      • 2018-07-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-28
      • 2015-11-24
      相关资源
      最近更新 更多