构造函数是在 C# 中的类中初始化不可为空属性的唯一方法吗?

Ily*_*dik 9 c# non-nullable nullable-reference-types

我已切换到在使用 C#8 的项目中启用可空。现在我有以下课程:

public class Request
{
    public string Type { get; set; }
    public string Username { get; set; }
    public string Key { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

编译器当然抱怨它不能保证这些属性不会为空。除了添加接受不可为空字符串的构造函数之外,我看不到任何其他方法来确保这一点。

这对于一个小班级来说似乎很好,但是如果我有 20 个属性,这是在构造函数中列出所有属性的唯一方法吗?是否有可能以某种方式使用初始化程序强制执行它:

var request = new Request { Type = "Not null", Username = "Not null" }; // Get an error here that Key is null
Run Code Online (Sandbox Code Playgroud)

PS 有一个很好的答案,建议使用 iniatlizer 来处理属性,但这并不总是适用于例如Type不能只是初始化为某个随机值的类型

Stu*_*tLC 7

对象初始值设定项语法实际上只是显式分配给字段或属性设置器的简写,即

var request = new Request { Type = "Not null", Username = "Not null" };
Run Code Online (Sandbox Code Playgroud)

相当于:

var request = new Request();   // <-- All properties are default
request.Type = "Not null";     // <-- Username and key are default
request.Username = "Not null"; // <-- Key is still default
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,Request实例仍然会经历几个状态,其中属性处于默认状态,这将适用于null字符串等引用类型,除非您按照其他答案在构造函数中分配不同的默认值。

另外,通过指定不同的默认值

public string Type { get; set; } = ""
public string Username { get; set; } = "";
public string Key { get; set; } = "";
Run Code Online (Sandbox Code Playgroud)

相当于在默认构造函数中分配这些值,即

public Request()
{
    Type = "";
    UserName = "";
    Key = "";
}
Run Code Online (Sandbox Code Playgroud)

正如您可以想象的那样,如果您随后立即使用对象初始值设定项语法再次更改该值,这有点浪费。

作为一种替代方法,如果您不需要可变类,我建议您提供一个或多个构造函数重载,然后为任何缺失的字段提供合适的非空默认值,然后使属性不可变,例如

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; }
}
Run Code Online (Sandbox Code Playgroud)

您现在可以实例化该类,而无需经历任何属性都为空的状态,并且无需中间默认分配的开销,例如

var myRequest = new Request(key: "SomeKey"); // <-- Username and Type are defaulted to ""
Run Code Online (Sandbox Code Playgroud)


Mil*_*ney 5

在定义中初始化它们

public string Type { get; set; } = ""
public string Username { get; set; } = "";
public string Key { get; set; } = "";
Run Code Online (Sandbox Code Playgroud)

对象初始值设定项语法“new Request { }”只是 new then 赋值的语法糖,所以不要认为在这种情况下你会出错