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;
}
我知道这是一个老问题,但这里是综合答案:
- 通过添加
<nullable>true<nullable>
标记,所有可空值都必须用 ?
标识
- 因为 1.,并且由于您没有将
?
添加到它们的类型中,所以 Colour
和 Flavour
都不能是 NULL
- 因为 2.,您必须提供一个构造函数来初始化
Colour
和 Flavour
的值 - 默认的无参数构造函数不会工作,因为它本身什么都不做,并且会 return 在 Colour
和 Flavour
中都具有 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
的默认值,它失败了
这就是为什么如果您不允许它们可以为空,则必须添加一个构造函数来初始化它们,并且您必须使用该构造函数
如果它们的类型是具有不同默认值的原始类型,则这将不适用 - 例如 int
或 double
。在那种情况下,默认的无参数构造函数将起作用。但是通过使用默认值为 NULL
的类型(如 string
或任何 object
派生类型),您可以通过添加 ?
使它们可以为空,或者您必须使用将它们初始化为 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;
}
我知道这是一个老问题,但这里是综合答案:
- 通过添加
<nullable>true<nullable>
标记,所有可空值都必须用?
标识
- 因为 1.,并且由于您没有将
?
添加到它们的类型中,所以Colour
和Flavour
都不能是NULL
- 因为 2.,您必须提供一个构造函数来初始化
Colour
和Flavour
的值 - 默认的无参数构造函数不会工作,因为它本身什么都不做,并且会 return 在Colour
和Flavour
中都具有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
的默认值,它失败了
这就是为什么如果您不允许它们可以为空,则必须添加一个构造函数来初始化它们,并且您必须使用该构造函数
如果它们的类型是具有不同默认值的原始类型,则这将不适用 - 例如 int
或 double
。在那种情况下,默认的无参数构造函数将起作用。但是通过使用默认值为 NULL
的类型(如 string
或任何 object
派生类型),您可以通过添加 ?
使它们可以为空,或者您必须使用将它们初始化为 NULL
.