具有对象初始值设定项语法的不可变类型



例如,我有一个不可变类型

class Contact
{
    // Read-only properties. 
    public string Name { get; }
    public string Address { get; }
}

我希望我可以使用对象初始化器语法来创建一个Contact

Contact a = new Contact { Name = "John", Address = "23 Tennis RD" };

但我不能。在这种情况下,有什么可能利用强大的对象初始化器语法的方法吗?

最接近的是带有可选参数的构造函数:

class Contact
{
    public string Name { get; }
    public string Address { get; }
    public Contact(string name = null, string address = null) {
        Name = name;
        Address = address;
    }
}

然后你可以用参数名称来调用它:

new Contact(
    name: "John",
    address: "23 Tennis RD"
)

语法与对象初始值设定项略有不同,但它同样可读;和IMO,这种差异是一件好事,因为构造函数参数往往表示不可变的属性。您可以按任何顺序指定参数,也可以省略一些参数,因此它与对象初始值设定项语法一样强大。

这确实需要一些额外的代码(定义构造函数,分配所有属性),所以这比对象初始化器语法更麻烦。但也不太可怕,不可变对象的价值是值得的

(值得一提的是,C#7可能会得到语法简单得多的不可变的"记录类型"。这些类型可能会也可能不会进入最终版本,但听起来很酷。)

这已经过时了,但随着C#9的发布,您可以使用init来实现所需的功能。

所以你的例子会变成:

class Contract
{
    // Read-only properties. 
    public string Name { get; init; }
    public string Address { get; init; }
}

然后你可以初始化:

// success!
Contract a = new Contract { Name = "John", Address = "23 Tennis RD" };

但在设置参数后,您仍然无法修改这些参数(因此它们仍然是只读的)。

// error!
a.Name = "Uncle Bob";

在后台,当您使用C#9之前的对象初始值设定项语法时,编译器将首先调用默认构造函数,然后设置您指定的属性值。显然,如果这些属性是只读的(即只有get方法),它就不能设置它们。仅限init的setter只允许在初始化时通过构造函数方法或对象初始化器语法设置值。

更多信息请点击此处:https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#init-仅设置

不可以,您不能将它与只读属性一起使用
以下是comparism中不同的属性和字段类型。

public class sometype {
    public int readonlyProp{
        get;
    }
    public int normalProp {
        get;
        set;
    }
    public const int constField = 3;
    public readonly int readonlyField = 3;
    public int normalField = 3;
    public void test() {
        sometype test = new sometype() { readonlyProp = 3}; //      Doesn't work -> Property or indexer is readonly
        sometype test1 = new sometype() { normalProp = 3 }; //      ok
        sometype test2 = new sometype() { constField = 3 }; //      Doesn't work -> Static field or property
        sometype test3 = new sometype() { readonlyField = 3 }; //   Doesn't work -> readonly field
        sometype test4 = new sometype() { normalField = 3 }; //     ok
    }
}

重要的是要理解const字段被认为是静态的,因此不是实例成员。由于对象初始值设定项用于实例成员,所以这不起作用。

对象初始化器将首先构造对象,然后设置属性值。它需要二传手。

这是的缩写

Contact a = new Contact();
a.Name = "John"; 
a.Address = "23 Tennis RD";

一旦构造了对象,就不能设置只读字段的值。要使该类不可变,您需要创建一个构造函数来获取这些值:

class Contact // Immutable class
{
    // Read-only properties. 
    public string Name { get; }
    public string Address { get; }
    public Contact(string name, string address)
    {
        this.Name = name;
        this.Address = address;
    }
}

最新更新