开发者

C#9.0中init访问器的实现

目录
  • 不控制可变性
  • 去掉set访问器
  • readonly
  • private
  • init访问器
  • init访问器在数据传输对象(DTO)和配置对象中的应用
    • 数据传输对象(DTO)
    • 配置对象
  • 开始使用init访问器
    • 参考

      不控制可变性

      下面是我们最常见的属性声明方式,允许属性在类的内部和外部都可以读取和修改

      public int Id { get; set; }
      
      namespace Demo
      {
          public class Company
          {
              public int Id { get; set; }
              public Company()
              {
              }
      
              public Company(int id)
              {
                  Id = id; // 可以在构造函数中设置
              }
      
              public void UpdateId(int newId)
              {
                  Id = newId; // 可以在类内部的方法中修改
              }
          }
      
          internal class Program
          {
              static void Main(string[] args)
              {
                  var company = new Company(1);
                  Console.WriteLine(company.Id); // 输出:1
                  company.Id = 2; // 可以在类外部修改
                  Console.WriteLine(company.Id); // 输出:2
      
                  // 使用对象初始化器语法,需要无参数构造函数
                  var newCompany = new Company { Id = 6 };
                  Console.WriteLine(newCompany.Id); /www.devze.com/ 输出:6
                  newCompany.UpdateId(4); // 通过方法更新
                  Console.WriteLine(newCompany.Id); // 输出:4
              }
          }
      }
      

      数据一致性问题:在某些情况下,属性不应该在对象生命周期内被随意修改。例如,Id属性通常用于唯一标识一个对象,如果允许在对象生命周期内修改它,可能导致数据不一致的问题

      去掉set访问器

      去掉set访问器,使得属性变为只读

      namespace Demo
      {
          public class Company
          {
              public int Id { get; }
      
              public Company()
              {
              }
      
              public Company(int id)
              {
                  Id = id; // 只能在构造函数中设置
              }
      
              // UpdateId 方法不能再修改 Id 属性,因为 get 访问器限制了修改
              // public void UpdateId(int newId)
              // {
              //     Id = newId; // 编译错误:不能修改只读属性
              // }
          }
      
          internal class Program
          {
              static void Main(string[] args)
         android     {
                  var company = new Company(1);
                  Console.WriteLine(company.Id); // 输出:1
      
                  // 下面这行代码会导致编译错误,因为 Id 属性是只读的
                  // company.Id = 2; // 编译错误:不能修改只读属性
      
                  // 下面这行代码会导致编译错误,因为对象初始化器不能设置只读属性
                  // var newCompany = new Company { Id = 6 }; // 编译错误:不能使用对象初始化器设置只读属性
      
                  var newCompany = new Company(6);
                  Console.WriteLine(newCompany.Id); // 输出:6
      
                  // newCompany.UpdateId(4); // 编译错误:不能修改只读属性
                  // Console.WriteLine(newCompany.Id); // 输出:4
              }
          }
      }
      

      readonly

      readonly指示只能在声明期间或在同一个类的构造函数中向字段赋值。 可以在字段声明和构造函数中多次分配和重新分配只读字段

      namespace Demo
      {
          public class Company
          {
              public readonly int Id = 666; // 使用 readonly 关键字,初始化默认值为 666
      
              public Company()
              {
                  // 无参数构造函数使用默认值 666
              }
      
              public Company(int id)
              {
                  Id = id; // 可以在构造函数中设置新的值
              }
      
              // UpdateId 方法不能再修改 Id 字段,因为 readonly 限制编程客栈了修改
              // public void UpdateId(int newId)
              // {
              //     Id = newId; // 编译错误:readonly 字段只能在构造函数中赋值
              // }
          }
      
          internal class Program
          {
              static void Main(string[] args)
              {
                  var initCompany = new Company();
                  Console.WriteLine(initCompany.Id); // 输出:666
      
                  var company = new Company(1);
                  Console.WriteLine(company.Id); // 输出:1
      
                  // 下面这行代码会导致编译错误,因为 Id 字段是只读的
                  // company.Id = 2; // 编译错误:readonly 字段在构造函数外不可修改
      
                  // 使用对象初始化器时不能设置 readonly 字段,因此需要使用构造函数
                  // var newCompany = new Company { Id = 6 }; // 编译错误:readonly 字段不能使用对象初始化器设置
              }
          }
      }
      

      private

      如果不想在类外部修改,我们也可以这样写

      namespace Demo
      {
          public class Company
          {
              public int Id { get; private set; }
      
              public Company() { }
      
              public Company(int id)
              {
                  Id = id;  // 可以在构造函数中设置
              }
      
              public void UpdateId(int newId)
              {
                  Id = newId;  // 可以在类内部的方法中修改
              }
          }
      
          internal class Program
          {
              static void Main(string[] args)
              {
                  var company = new Company(1);
                  Console.WriteLine(company.Id); //输出:1
                  company.UpdateId(4);
                  Console.WriteLine(company.Id); // 输出:4
      
                  var newCompany = new Company();
                  //company.Id = 2; // 编译错误:外部不能修改
              }
          }
      }
      
      

      private set访问器,允许类内部修改属性,但外部不可修改,即保护内部状态,常见应用场景:计数器、状态管理等

      init访问器

      init访问器允许属性在对象初始化时设置,但在对象初始化完成后就不能再修改

      using System;
      
      namespace Demo
      {
          public class Company
          {
              public int Id { get; init; } // 使用 init 访问器,使得属性在初始化后不可修改
            
              public Company()
              {
              }
      
              public Company(int id)
              {
                  Id = id; // 可以在构造函数中设置
              }
      
              // UpdateId 方法不能再修改 Id 属性,因为 init 访问器限制了修改
              // public void UpdateId(int newId)
              // {
              //     Id = newId; // 编译错误:初始化后不可修改
              // }
          }
      
          internal class Program
          {
              static void Main(string[] args)
              {
                  var company = new Company(1);
                  Console.WriteLine(company.Id); // 输出:1
      
                  // 下面这行代码会导致编译错误,因为 Id 属性是只读的
                  // company.Id = 2; // 编译错误:初始化后不可修改
      
                  var newCompany = new Company { Id = 3 }; // 使用对象初始化器
                  Console.WriteLine(newCompany.Id); // 输出:3
      
                  // 下面这行代码会导致编译错误,因为 Id 属性是只读的
                  // newCompany.Id = 4; // 编译错误:初始化后不可修改
              }
          }
      }
      

      init访问器在数据传输对象(DTO)和配置对象中的应用

      数据传输对象(DTO)

      数据传输对象(DTO)是用于在不同系统或不同层之间传递数据的简单对象。这些对象通常不包含任何业务逻辑,仅用于封装数据。使用init访问器可以确保DTO在创建后其属性不会被修改,从而保证传输数据的完整性和一致性

      namespace Demo
      {
          public class CustomerDto
          {
              public int Id { get; init; }
              public string Name { get; init; }
              public string Email { get; init; }
          }
      
          internal class Program
          {
              static void Main(string[] args)
              {
                  // 使用对象初始化器创建DTO实例
                  var customer = new CustomerDto
                  {
                      Id = 1,
                      Name = "John Doe",
                      Email = "john.doe@example.com"
                  };
      
                  Console.WriteLine($"Customer: {customer.Id}, {customer.Name}, {customer.Email}"); // 输出:Customer: 1, John Doe, john.doe@example.com
      
                  // customer.Name = "Jane Doe"; // 编译错误:初始化后不可修改
              }
          }
      }
      

      配置对象

      配置对象通常用于存储应用程序的配置设置。这些设置在应用程序启动时加载,并在整个应用程序生命周期内保持不变。使用init访问器可以确保配置对象在初始化后,其配置属性不会被修改,从而防止在应用程序运行过程中意外更改配置

      public class AppConfig
      {
          public string ConnectionString { get; init; }
          public int MaxRetryCount { get; init; }
          public bool EnableLogging { get; init; }
      }
      
      internal class Program
      {
          static void Main(string[] args)
          {
              // 使用对象初始化器创建配置对象实例
              var config = new AppConfig
              {
                  ConnectionString = "Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;",
                  MaxRetryCount = 5,
                  EnableLogging = true
              };
              // 输出:Config: ConnectionString=Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;, MaxRetryCount=5, EnableLogging=True
              Console.WriteLine($"Config: ConnectionString={cpythononfig.ConnectionString}, MaxRetryCount={config.MaxRetryCount}, EnableLogging={config.EnableLogging}");
      
              // config.MaxRetryCount = 10; // 编译错误:初始化后不可修改
          }
      }
      

      开始使用init访问器

      在C#9.0中,引入了init访问器。使用此功能,有两个先决条件:

      • 安装.NET 5+ SDK
      • 安装Visual Studio 2019或更高版本

      参考

      • C# Init-Only Setters 属性 — C# Init-Only Setters Property (loginradijavascriptus.com)
      • C#中init()方法是起什么作用啊-CSDN社区
      • init 关键字 - C# reference | Microsoft Learn
      • 一看就懂——C#中readonly关键字_c# readonly关键字-CSDN博客
      • 只读关键字 - C# reference | Microsoft Learn
      • C#9.0:Init - Hello-Brand - 博客园 (cnblogs.com)

      到此这篇关于C#9.0中init访问器的实现的文章就介绍到这了,更多相关C# init访问器内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

      0

      上一篇:

      下一篇:

      精彩评论

      暂无评论...
      验证码 换一张
      取 消

      最新开发

      开发排行榜