C#9 + .NET5,启用可为空:是否可以在不使用 null 的情况下使用具有不可空属性的对象初始化程序!?

C#9 + .NET5, nullable enabled: is it possible to use the object initialiser with non nullable properties without using null!?

我正在用 NET 5.0 测试 c# 9.0,但有些东西我不明白。我启用了 <nullable>enable</nullable>.

如果我写一个class

public class Potato {
    public string Colour { get; set;  }

    public string Flavour { get; set; }
}

我收到警告CS8618: Non-nullable propery 'Colour' must contain a non-null value when existing constructor. Consider declaring the propery as nullable.我不想声明它可为空,这就是我启用该标签的原因...

然后,我声明构造函数:

public class Potato
{
    public Potato(string colour, string flavour)
    {
        this.Colour = colour;
        this.Flavour = flavour;
    }

    public string Colour { get; set; }

    public string Flavour { get; set; }
}

到目前为止一切顺利。现在我想使用对象初始化程序创建一个 Potato 对象:

var sweetPotato = new Potato { 
    Colour = "orange",
    Flavour = "tasty",
};

现在我收到了投诉 CS7036: There is no argument given that corresponds to the required formal parameter 'colour' of 'Potato.Potato(string, object)。所以,它尝试使用我显式声明但我没有引入参数的构造函数。我应该做的:

var sweetPotato = new Potato(
    colour: "orange",
    flavour: "tasty");

但这里我没有使用对象初始化程序。

另一种选择是将 class 声明为

public class Potato
{
    public string Colour { get; set; } = null!;

    public string Flavour { get; set; } = null!;
}

null! 元素,但这允许一些奇怪的事情,例如:

var sweetPotato = new Potato()
{
    Colour = "orange",
};

我认为这非常奇怪。我声明了 2 个不可为 null 的属性,多亏了 null!,我可以用一个 属性 加载对象,但不能加载第二个。这破坏了我的可空标签!

那么我的问题是:如果启用了可空标记,是否可以使用具有不可空属性的对象初始化程序?

如果不是,我认为对于具有不可空属性的 classes,不涉及任何 null!,默认构造函数不应该是空构造函数,而是带有所有参数的构造函数,并且只要初始化所有不可为 null 的属性,就必须可以使用对象初始化器形式初始化对象。

string 的默认值为空。由于您的 属性 声明没有定义默认值,它们将默认为 default,在 string 的情况下恰好是 null。问题是您没有将类型声明为 nullable.

解决方法是赋一个默认值,比如String.Empty:

public class Potato
{
    public string Colour { get; set; } = String.Empty;

    public string Flavour { get; set; } = String.Empty;
}

我知道这是一个老问题,但这里是综合答案:

  1. 通过添加 <nullable>true<nullable> 标记,所有可空值都必须用 ?
  2. 标识
  3. 因为 1.,并且由于您没有将 ? 添加到它们的类型中,所以 ColourFlavour 都不能是 NULL
  4. 因为 2.,您必须提供一个构造函数来初始化 ColourFlavour 的值 - 默认的无参数构造函数不会工作,因为它本身什么都不做,并且会 return 在 ColourFlavour 中都具有 NULL 的对象,因为这是它们类型的默认值,您要求编译器不允许

下面的代码片段:

var sweetPotato = new Potato { 
    Colour = "orange",
    Flavour = "tasty",
};

使用默认的无参数构造函数,因此无法使用。它是 shorthand 等同于:

var sweetPotato = new Potato(); // sweetPotato has Colour and Flavour NULL
sweetPotato.Colour = "orange";  // sweetPotato still has Flavour NULL
sweetPotato.Flavour = "tasty";

如您所见,它会先创建对象(使用默认值),然后再赋值。但是由于您不允许 NULL 的默认值,它失败了

这就是为什么如果您不允许它们可以为空,则必须添加一个构造函数来初始化它们,并且您必须使用该构造函数

如果它们的类型是具有不同默认值的原始类型,则这将不适用 - 例如 intdouble。在那种情况下,默认的无参数构造函数将起作用。但是通过使用默认值为 NULL 的类型(如 string 或任何 object 派生类型),您可以通过添加 ? 使它们可以为空,或者您必须使用将它们初始化为 NULL.

以外的构造函数