【问题标题】:Satisfy or silence nullable generic type property warning满足或静音可为空的泛型类型属性警告
【发布时间】:2019-12-06 14:43:31
【问题描述】:

在 C#8.0 中使用可为空的引用类型,给出这个简化的代码,其中 T 可以是任何值类型或引用类型,并且空值是引用类型 T 实例的有效值:

public class C<T>
{
    public T P { get; set; }
}

编译器发出警告CS8618 "Non-nullable property 'P' is uninitialized. Consider declaring the property as nullable."。 我怎样才能满足编译器并消除此警告(不抑制 CS8618)?

是否有我可以应用的属性或类型参数约束?那怎么办?

我想出的最好的是

public T P { get; set; } = default!;

但我希望有一种方法可以在不使用 null-forgiving/"dammit" 运算符 ('!') 的情况下做到这一点。

注意:您不能将属性类型声明为T? - CS8627。此外,这意味着返回的任何值类型都是Nullable&lt;T&gt;,这不是预期的。 (Read more about this e.g. here.)


编辑:我注意到这也有效:

public class C<T>
{
    public C()
    {
        P = default;
    }
    [AllowNull]
    public T P { get; set; }
}

但是我更喜欢使用自动属性初始化器。

【问题讨论】:

  • 首先你需要决定想要做什么。在第一次设置之前,you 希望该值包含什么?一些默认实例?它应该是只读的吗? get; 是否有可能返回 null?也许您应该使用Option 风格的类型,它可以有一个值或者是None
  • 每个选项都可以以不同的方式实现,通过构造函数、可空性属性或自定义选项结构like this one
  • 我希望属性值是默认值。 IE。对于int,它应该是'0',对于object,它应该是'null',就好像这个类是用这些类型中的任何一个而不是泛型类型参数定义的一样。
  • 那是什么 default ?它不能为 null 并且仍然是不可为 null 的引用。这就是该功能的全部意义所在。如果您希望它为空,请将其设置为T?。如果您真的想利用不可为空的类型,请修改您的设计,使其不需要需要空值
  • 我建议使用class 约束。泛型类型很少需要同时支持类和结构。由于可空性对它们中的每一个都有不同的作用,因此您会立即遇到此问题。否则,也许可以尝试使用 [AllowNull]default!

标签: c# generics nullable c#-8.0 nullable-reference-types


【解决方案1】:

基本上,classstruct 可空性根本不兼容,无法组合。

您的选择包括:

  • 保持你的类完全通用;因此,TT? 在您的班级内没有区别。这仍然允许C&lt;int&gt;C&lt;int?&gt;,只是不允许T?

  • 限制为 classstruct,具体取决于您的要求。

  • 编写两个单独的类,一个用于结构,一个用于引用类型。

如果足够简单,编写两个类也不错。您也许可以将非泛型部分推入基类以避免过多重复。

【讨论】:

    【解决方案2】:

    当您实例化您的类时,属性 P 的值将为空,这就是您看到警告的原因。

    您需要确保在实例化类时该值不为空,唯一的方法是定义一个构造函数并为P 提供值。由于T 是一个泛型类型,您有两种选择:

    1. 将值作为构造函数参数传递或
    2. 约束 T 以便能够创建新实例
    // Option #1
    public class C<T>
    {
       C(T p)
       {
           P = p
       }
    
       public T P { get; set; }
    }
    
    // option #2:
    public class C<T> where T : new()
    {
       C()
       {
           P = new T()
       }
    
       public T P { get; set; }
    }
    
    

    【讨论】:

    • 起初我打算写一个与此类似的答案,但我认为问题在于 OP 确实 实际上希望该属性可以为空。问题是你不能在没有classstruct 约束的情况下使用T? 将其标记为可空,因为它们的可空性不兼容。
    • 是的,如果属性应该可以为空,T? 是正确的解决方案
    猜你喜欢
    • 2012-03-27
    • 2020-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-27
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    相关资源
    最近更新 更多