3

C# 9 新特性——init only setter

 3 years ago
source link: https://www.cnblogs.com/weihanli/p/14214401.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

C# 9 新特性——init only setter

Intro#

C# 9 中新支持了 init 关键字,这是一个特殊的 setter,用来指定只能在对象初始化的时候进行赋值,另外支持构造器简化的写法,比如:Target-typed new expression 在已知类型的情况下可以使用 new() 来代表构造方法的简化用法,可以简化字段的声明,也可以简化一次声明多个相同类型的变量

Sample#

来看一个示例,我们定义一个测试用的 Person 类,测试代码如下:

public class Person
{
    public int Age { get; init; }

    public string Name { get; init; }

    public string Description { get; set; }

    public override string ToString()
    {
        return $"Name:{Name}(Age:{Age})";
    }
}

init 是一个特殊的 setter 适用于实例属性,被标记为 init 的属性,只能在实例化的时候通过初始化器来赋值,实例化操作完成后不允许再修改值。

var p1 = new Person()
{
    Name = "Michael",
    Age = 10
};
Console.WriteLine(p1);
// compiler error,不能对 init 的字段再赋值
// p1.Age = 12;

// Target-Typed new expression, C#9 新特性
Person p2 = new()
{
    Name = "Jane",
    Age = 10,
}, p3 = new()
{
    Name = "Alice"
};
Console.WriteLine(p2);
Console.WriteLine(p3);

init 的等效写法,init 类似于 set ,但是 init 对应的字段会是一个 readonly 的字段,来保证只能在构造器中或者初始化器中被赋值,另外编译器会做检查如果是 init,会有一个特殊的标识,在初始化后再赋值的时候就会报错,类似于下面这样:

internal class TestInitModel
{
    private readonly string _name;

    public string Name
    {
        get => _name;
        init => _name = value;
    }
}

我们以上面的 Person 为例来看一下生成 IL 代码的区别:

可以看到声明为 init 的 属性会比普通的 set 多出来一个修饰符,这是由编译器去生成的,编译器也会根据此去判断是否是在初始化的时候赋值,如果不是就会报错。

序列化是否会有问题呢,我们来测试一下,可以看到 model1 是被正常赋值(这里的 ToJson/JsonToObject是基于 Newtonsoft.JsonJsonConvert 封装的扩展方法)

More#

我觉得 init 为我们带来的好处在于,可以在初始化的时候赋值而非直接通过构造器赋值,如果希望一个属性只能 get ,不在初始化之外的地方被赋值,之前我的做法都是在构造器里初始化,只保留一个 getter,没有 setter,有了这个支持之后就可以不需要修改构造方法比较方便的使用了

Reference#


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK