具有对象初始化器语法的不可变类型

时间:2016-05-08 21:16:37

标签: c# properties

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

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

我希望我可以使用对象初始化程序语法来创建联系人

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

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

4 个答案:

答案 0 :(得分:5)

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

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可能会得到immutable "record types"更简单的语法。这些可能会或可能不会进入最终版本,但它们听起来很酷。)

答案 1 :(得分:2)

现在已过时,但是随着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设置程序允许仅在初始化时通过构造函数方法或对象初始化程序语法设置值。

更多信息可在此处找到:https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-9#init-only-setters

答案 2 :(得分:1)

不,你不能将它与readonly属性一起使用 以下是比较中不同的属性和字段类型。

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字段被认为是静态的,因此不是实例成员。由于对象初始值设定项用于实例成员,因此无效。

答案 3 :(得分:0)

对象初始值设定项将首先构造对象,然后设置属性值。 它需要制定者。

它的简写:

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

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

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;
    }
}