C#9.0中init访问器的实现

 更新时间:2024年05月29日 09:22:15   作者:VinciYan  
本文主要介绍了C#9.0中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); // 输出: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)
        {
            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={config.ConnectionString}, MaxRetryCount={config.MaxRetryCount}, EnableLogging={config.EnableLogging}");

        // config.MaxRetryCount = 10; // 编译错误:初始化后不可修改
    }
}

开始使用init访问器

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

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

参考

到此这篇关于C#9.0中init访问器的实现的文章就介绍到这了,更多相关C# init访问器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • c#闭包使用方法示例

    c#闭包使用方法示例

    这篇文章主要介绍了如何使用C#的闭包功用,例子很简单,大家参考使用吧
    2013-11-11
  • 用 FieldMask 提高 C# gRpc 的服务性能

    用 FieldMask 提高 C# gRpc 的服务性能

    这篇文章主要介绍了用 FieldMask 提高 C# gRpc 的服务性能,FieldMask 是一个 protobuf 消息,包含一个名为 paths 的字段,用于指定用于指定读取操作返回或更新操作修改的字,下文详细内容,需要的朋友可以参考一下
    2022-03-03
  • C#使用Linq实现简单去重处理

    C#使用Linq实现简单去重处理

    这篇文章主要为大家详细介绍了C#如何使用Linq实现简单去重处理功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-02-02
  • C#二维数组与多维数组的具体使用

    C#二维数组与多维数组的具体使用

    本文主要介绍了C#二维数组与多维数组的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • c#操作附加数据库的方法

    c#操作附加数据库的方法

    这篇文章主要介绍了c#操作附加数据库的方法,涉及C#针对附加数据库的相关操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-08-08
  • c#字符串编码编码(encoding)使用方法示例

    c#字符串编码编码(encoding)使用方法示例

    System.Text提供了Encoding的抽象类,这个类提供字符串编码的方法。使Unicode字符数组的字符串,转换为指定编码的字节数组,或者反之,看下面的例子
    2013-12-12
  • C# 调用WebApi的实现

    C# 调用WebApi的实现

    这篇文章主要介绍了C# 调用WebApi的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • 使用C#代码在Word文档中设置段落缩进

    使用C#代码在Word文档中设置段落缩进

    本文介绍了如何通过编程方式在Word文档中设置段落缩进,主要左缩进、右缩进、首行缩进和悬挂缩进等内容,详细解释了设置段落缩进的具体步骤和代码实现,提供了示例代码帮助读者更好地理解和实现,需要的朋友可以参考下
    2026-04-04
  • C# WinForm窗口闪烁问题的多种解决方法

    C# WinForm窗口闪烁问题的多种解决方法

    在 C# WinForm 应用程序中,窗体或控件的闪烁问题通常由频繁的重绘操作、未启用双缓冲、或未优化绘制逻辑导致,以下是解决 C# WinForm 窗口闪烁问题的多种方法,并通过代码讲解的非常详细,需要的朋友可以参考下
    2025-07-07
  • C#使用Post调用接口并传递json参数

    C#使用Post调用接口并传递json参数

    这篇文章主要介绍了C#使用Post调用接口并传递json参数,具有很好的参考价值,希望对大家有所帮助。
    2022-06-06

最新评论