构造函数是在 C# 中初始化类中不可为空的属性的唯一方法吗?
Posted
技术标签:
【中文标题】构造函数是在 C# 中初始化类中不可为空的属性的唯一方法吗?【英文标题】:Is constructor the only way to initialize non-nullable properties in a class in C#? 【发布时间】:2020-04-19 04:58:39 【问题描述】:我已切换到在使用 C#8 的项目中启用可为空。现在我有以下课程:
public class Request
public string Type get; set;
public string Username get; set;
public string Key get; set;
编译器当然抱怨它不能保证这些属性不会为空。除了添加一个接受不可为空字符串的构造函数之外,我看不到任何其他方法来确保这一点。
这对于一个小类来说似乎很好,但是如果我有 20 个属性,这是在构造函数中将它们全部列出的唯一方法吗?是否有可能以某种方式例如用初始化器强制它:
var request = new Request Type = "Not null", Username = "Not null" ; // Get an error here that Key is null
附:有一个很好的答案建议对属性使用 iniatlizer,但这并不总是有效,例如对于类型,例如Type
不能只是初始化为某个随机值
【问题讨论】:
初始化器创建一个 empty 对象,然后设置值。它与接受参数的构造函数不同。代码也不是less。你真的要使用对象初始化器吗? @PrasadTelkikar 我不认为你说的是真的。我至少收到一个编译器警告,我必须自己初始化它。或者即使是真的,也不会阻止警告 如果这样做,您可以在属性本身中设置默认值。您可以添加属性告诉编译器属性一旦设置就不会为空,例如NotNull
@PanagiotisKanavos 不,这只是我想到的一种理论上的可能性,我只是真的想了解新的不可为空类型的正确行动方案。我真的不想在那里接受 null 因为我事先知道它是无效的,但是用很多参数编写构造函数似乎有点太多了
@IlyaChernomordik 选项在那里,但你必须决定你真正想要什么。这些“可选”属性是否具有默认值? props 或字段 必须 被初始化,null
现在可能是也可能不是适当的默认值。
【参考方案1】:
对象初始化语法实际上只是显式分配给字段或属性设置器的简写,即
var request = new Request Type = "Not null", Username = "Not null" ;
相当于:
var request = new Request(); // <-- All properties are default
request.Type = "Not null"; // <-- Type and key are default
request.Username = "Not null"; // <-- Key is still default
如您所见,Request
实例仍会经历几个状态,其中属性处于默认状态,除非您在构造函数中分配不同的默认值,否则对于字符串等引用类型,该状态将为 null
根据其他答案。
另外,通过指定不同的默认值
public string Type get; set; = ""
public string Username get; set; = "";
public string Key get; set; = "";
相当于在默认构造函数中分配这些值,即
public Request()
Type = "";
UserName = "";
Key = "";
您可以想象,如果您随后立即使用对象初始化器语法再次更改值,这有点浪费。
作为替代方案,如果您不需要可变类,我建议您提供一个或多个构造函数重载,然后为任何缺少的字段提供合适的非空默认值,然后创建属性不可变例如
public class Request
public Request(string type = "", string userName = "", string key = "")
Type = type;
Username = userName;
Key = key;
public string Type get; // <-- No setter = immutable.
public string Username get;
public string Key get;
您现在可以实例化该类,而无需经历任何属性为空的状态,也无需中间默认分配的开销,例如
var myRequest = new Request(key: "SomeKey"); // <-- Username and Type are defaulted to ""
【讨论】:
C#9 有一个新的“init”关键字,但它还没有帮助。这里有一个 github 问题 (github.com/dotnet/roslyn/issues/44889) 可能会解决它,以便我们将来可以使用初始化语法【参考方案2】:在定义中初始化它们
public string Type get; set; = ""
public string Username get; set; = "";
public string Key get; set; = "";
对象初始化语法“new Request ”只是 new then 赋值的语法糖,所以不要认为在这种情况下你会出错
【讨论】:
只有2种方式吗?构造函数还是直接初始化?附言带有受保护构造函数的类型,例如Type
,那么它只是构造函数呢?以上是关于构造函数是在 C# 中初始化类中不可为空的属性的唯一方法吗?的主要内容,如果未能解决你的问题,请参考以下文章