C# init 关键字的使用

总目录


前言


一、C#9.0 以前不可变数据的实现方式

1. 声明readonly变量

csharp 复制代码
    internal class Program
    {
        static void Main(string[] args)
        {
            Class1 class1 = new Class1();
            //取值,输出结果:Jack
            Console.WriteLine(class1.Name);
            
            Console.ReadKey();
        }
    }

    public class Class1
    {
        public readonly string Name = "Tom";

        public Class1()
        {
            Name = "Jack";
        }

        public void Test()
        {
           // Name = "Tom";
        }
    }

通过代码发现,readonly的变量,我们可以在声明变量和构造函数中赋初始值,其余的地方均会报错。

2. 仅包含 get 访问器的属性

csharp 复制代码
    internal class Program
    {
        static void Main(string[] args)
        {
            Class1 class1 = new Class1();
            //取值,输出结果:Jack
            Console.WriteLine(class1.Name);

            Console.ReadKey();
        }
    }

    public class Class2
    {
        public string Name { get; } = "Tom";

        public Class2()
        {
            Name = "Jack";
        }

        public void Test()
        {
            //Name = "Tom";
        }
    }

只读属性的简化过程

csharp 复制代码
    public class Class2
    {
        //不同只读的编写方式

        //只读属性方式1
        public string Name { get; } = "Tom";

        //只读属性方式2
        public string NickName { get { return "测试昵称"; } }

        //只读属性方式3
        public string NickName2 { get => "测试昵称2"; }

        //只读属性方式4
        public string Phone => "151********";

        public Class2()
        {
            Name = "Jack";
        }
    }

3. 参数化构造函数

以上在构造函数中赋初始值的方式,可以通过参数化构造函数优化一下,使实例化更为灵活。

csharp 复制代码
    internal class Program
    {
        static void Main(string[] args)
        {
            Class1 class1 = new Class1("Hack","151********");

            //赋值,由于是只读的,因此会报错
            //class1.Name = "jack";

            //取值,输出结果:Hack - 151********
            Console.WriteLine($"{class1.Name} - {class1.Phone}");

            Console.ReadKey();
        }
    }

    public class Class1
    {
        public string Name { get; }
        public string Phone { get; } 

        public Class1()
        {

        }
        public Class1(string name, string phone)
        {
            Name = name;
            Phone = phone;
        }
    }

这种方式是可行的,也达到只读的目的,但是代码量多,需要增加额外的构造方法来实现初始化赋值,并且如果字段越多,带参构造函数也会越大,开发工作量也越大,更不好维护。

为了改变这种状态,C#9.0提供了一种解决方案:在对象初始换的时候就配置为只读的方式。

2. C# 9.0 init 实现不可变数据

1. init 的使用

  • init是扩大readonly实例字段的赋值方式,C#9之前readonly实例字段只能在字段初始值设定项和实例构造函数中赋值(静态只读字段还是只有两种赋值方式)。
  • C#9 推出init 以后,readonly实例字段可以多一种赋值方式,可以在对象初始值设定项中赋值。
    • 如下面案例中的Name属性 Class1 class1 = new Class1() { Name="名称3"};
csharp 复制代码
    internal class Program
    {
        static void Main(string[] args)
        {
            Class1 class1 = new Class1() { Name="名称3"};

            //此处赋值会报错
            //class1.Name = "";    
            Console.WriteLine($"Class1.Name的值为:{class1.Name}"); //Class1.Name的值为:名称3
        }
    }

    class Class1
    {
        public string Name { get; init; } = "名称1";

        public Class1()
        {
            Name = "名称2";
        }
    }

2. private set、read only 和 init 属性之间的区别

通过一个案例说明

csharp 复制代码
class PersonPrivateSet
{
    public string FirstName { get; private set; }
    public string LastName { get; private set; }
    public PersonPrivateSet(string first, string last) => (FirstName, LastName) = (first, last);

    public void ChangeName(string first, string last) => (FirstName, LastName) = (first, last);
}

class PersonReadOnly
{
    public string FirstName { get; }
    public string LastName { get; }
    public PersonReadOnly(string first, string last) => (FirstName, LastName) = (first, last);
}

class PersonInit
{
    public string FirstName { get; init; }
    public string LastName { get; init; }
}
csharp 复制代码
PersonPrivateSet personPrivateSet = new("Bill", "Gates");
PersonReadOnly personReadOnly = new("Bill", "Gates");
PersonInit personInit = new() { FirstName = "Bill", LastName = "Gates" };
  • private set 版本和 read only 版本都需要调用方使用添加的构造函数来设置 name 属性。
  • 通过 private set 版本,人员可在构造实例后更改其名称。
  • init 版本不需要构造函数。 调用方可使用对象初始值设定项初始化属性:

结语

回到目录页:C# 知识汇总

希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。


参考资料:
C# init用法
C#9.0:Init
init(C# 参考)

相关推荐
呆呆的小草32 分钟前
Cesium距离测量、角度测量、面积测量
开发语言·前端·javascript
uyeonashi34 分钟前
【QT系统相关】QT文件
开发语言·c++·qt·学习
MasterNeverDown1 小时前
在C#中的乐观锁和悲观锁
c#·并发·
全栈小52 小时前
【C#】Quartz.NET怎么动态调用方法,并且根据指定时间周期执行,动态配置类何方法以及Cron表达式,有请DeepSeek
c#·.net·quartz.net·deepseek
冬天vs不冷2 小时前
Java分层开发必知:PO、BO、DTO、VO、POJO概念详解
java·开发语言
sunny-ll2 小时前
【C++】详解vector二维数组的全部操作(超细图例解析!!!)
c语言·开发语言·c++·算法·面试
猎人everest2 小时前
Django的HelloWorld程序
开发语言·python·django
嵌入式@秋刀鱼3 小时前
《第四章-筋骨淬炼》 C++修炼生涯笔记(基础篇)数组与函数
开发语言·数据结构·c++·笔记·算法·链表·visual studio code
嵌入式@秋刀鱼3 小时前
《第五章-心法进阶》 C++修炼生涯笔记(基础篇)指针与结构体⭐⭐⭐⭐⭐
c语言·开发语言·数据结构·c++·笔记·算法·visual studio code
别勉.3 小时前
Python Day50
开发语言·python