构造函数是在 C# 的 class 中初始化不可空属性的唯一方法吗?
Is constructor the only way to initialize non-nullable properties in a class in C#?
我已在使用 C#8 的项目中切换为启用可为空。现在我有以下 class:
public class Request
{
public string Type { get; set; }
public string Username { get; set; }
public string Key { get; set; }
}
编译器当然会抱怨它不能保证这些属性不会为空。除了添加接受不可为 null 的字符串的构造函数之外,我看不到任何其他方法可以确保这一点。
这对于小型 class 来说似乎不错,但是如果我有 20 个属性,这是在构造函数中列出所有属性的唯一方法吗?是否有可能以某种方式例如使用初始化程序强制执行它:
var request = new Request { Type = "Not null", Username = "Not null" }; // Get an error here that Key is null
P.S。有一个很好的答案建议对属性使用 iniatlizer,但这并不总是有效,例如对于类型,例如Type
不能只初始化为某个随机值
在定义中初始化它们
public string Type { get; set; } = ""
public string Username { get; set; } = "";
public string Key { get; set; } = "";
对象初始化语法 "new Request { }" 只是 new then 赋值的语法糖,所以在这种情况下不要认为你会出错
对象初始化器语法实际上只是显式分配给字段或 属性 setter 的简写,即
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 = "";
}
如您所想,如果您随后立即使用对象初始化语法再次更改值,这有点浪费。
作为替代方案,如果您不需要可变 class,我建议您提供一个或多个构造函数重载,然后为任何缺失的字段提供合适的非空默认值,然后使属性不可变,例如
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; }
}
您现在可以实例化 class,而无需经历任何属性都为 null 的状态,也无需中间默认赋值的开销,例如
var myRequest = new Request(key: "SomeKey"); // <-- Username and Type are defaulted to ""
我已在使用 C#8 的项目中切换为启用可为空。现在我有以下 class:
public class Request
{
public string Type { get; set; }
public string Username { get; set; }
public string Key { get; set; }
}
编译器当然会抱怨它不能保证这些属性不会为空。除了添加接受不可为 null 的字符串的构造函数之外,我看不到任何其他方法可以确保这一点。
这对于小型 class 来说似乎不错,但是如果我有 20 个属性,这是在构造函数中列出所有属性的唯一方法吗?是否有可能以某种方式例如使用初始化程序强制执行它:
var request = new Request { Type = "Not null", Username = "Not null" }; // Get an error here that Key is null
P.S。有一个很好的答案建议对属性使用 iniatlizer,但这并不总是有效,例如对于类型,例如Type
不能只初始化为某个随机值
在定义中初始化它们
public string Type { get; set; } = ""
public string Username { get; set; } = "";
public string Key { get; set; } = "";
对象初始化语法 "new Request { }" 只是 new then 赋值的语法糖,所以在这种情况下不要认为你会出错
对象初始化器语法实际上只是显式分配给字段或 属性 setter 的简写,即
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 = "";
}
如您所想,如果您随后立即使用对象初始化语法再次更改值,这有点浪费。
作为替代方案,如果您不需要可变 class,我建议您提供一个或多个构造函数重载,然后为任何缺失的字段提供合适的非空默认值,然后使属性不可变,例如
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; }
}
您现在可以实例化 class,而无需经历任何属性都为 null 的状态,也无需中间默认赋值的开销,例如
var myRequest = new Request(key: "SomeKey"); // <-- Username and Type are defaulted to ""