zoukankan      html  css  js  c++  java
  • C#中的属性

    来源:https://blog.guoqianfan.com/2019/12/07/properties-in-csharp/

    前言

    C#属性是字段的扩展,它配合C#中的字段使用,用以构造一个安全的应用程序。

    属性提供了灵活的机制来读取、编写或计算私有字段的值,可以像使用公共数据成员一样使用属性,但实际上它们是称做“访问器”的特殊方法,其设计目的主要是为了实现面向对象(Object Oriented, OO)中的封装思想。

    根据该思想,字段最好设为private, 一个设计完善的类最好不要直接把字段声明为公有或受保护的,以阻止客户端直接进行访问,其中一个主要原因是,客户端直接对公有字段进行读写,使得我们无法对字段的访问进行灵活的控制,比如控制字段只读或者只写将很难实现。

    —— 姜晓东《C# 4.0权威指南》-【9.4.5 属性

    声明和使用读/写属性(旧)

    这种方式是C#中最基础的,也是最早出现的读写属性的方式。本文中我暂时称它为老式的读/写属性

    该方式允许我们在对属性读/写时,进行一些操作/计算

    声明属性

    首先要声明一个私有字段,然后使用get访问器读取私有字段的值,使用set访问器为私有字段赋值

    示例代码如下:

    class Person
    {
        private string _name = "N/A";
        private int _age = 0;
    
        // Declare a Name property of type string:
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
            }
        }
    
        public int Age
        {
            get
            {
                return _age;
            }
            set
            {
                _age = value > 120 ? 120 : value;
            }
        }
    }
    

    使用属性

    属性的使用很简单。外部可以直接对属性进行读取或赋值,就像使用类的公共字段一样。(注意:这里假设属性都是公共读写的,实际使用中要注意属性的可访问性

    //==========外部访问属性==========
    Person person = new Person();
    person.Name = "Bob";//为属性赋值
    person.Age = 18;//为属性赋值
    
    //读取属性的值
    int age = person.Age;
    

    备注

    1. 在属性的set方法中,value变量是很特殊的, 它代表用户指定的值。

    自动实现的属性(新)

    当属性访问器中不需要任何其他逻辑时,我们可以使用自动实现的属性,它会使属性声明更加简洁。

    自动实现的属性在编译后,也是生成了老式的读/写属性

    VS中使用快捷键prop可以快速生成自动实现属性。

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    

    其他

    自动实现的属性的本质

    自动实现的属性在编译后,也是生成了老式的读/写属性

    这个是编译器自动帮我们做的,可以通过查看编译后生成的IL代码(又称作MSILCIL)来验证。

    不过本人能力有限,就不分析了。这里推荐大家阅读 《C# 4.0权威指南》 中的【9.4.5 属性】一节,该章节详细分析了自动实现的属性经过编译后生成的IL代码。

    属性初始化器

    在 C# 6 和更高版本中,你可以像字段一样初始化自动实现属性:

    public string FirstName { get; set; } = "Jane";  
    

    上述代码经过编译后,是在构造函数中,为属性赋值的。(来源)

    只读属性默认初始化

    在 C# 6 中,可以去掉set访问器,使属性变为只读属性。

    public string Name { get; } = "hello world";
    

    上述代码经过编译后,生成的属性关联字段是readonly的,并且仍然是在构造函数中为属性赋值的:private readonly string kBackingField;。(来源)

    这种方式下,生成的属性是没有 setter 的(即使用反射,也无法设置值,setter 根本就不存在)。这个属性只能在构造函数中,或者结合特性赋值。(来源)

    表达式体属性

    自 C# 6 起,支持方法、运算符和只读属性的表达式主体定义。

    自 C# 7.0 起,支持构造函数、终结器、属性和索引器访问器的表达式主体定义。

    在 C# 6 中,可以把只读属性改写为表达式体的形式。

    在 C# 7.0 中,可以把某个访问器改写为表达式体的形式。

    只读属性的表达式体形式属性(访问器)的表达式体形式是不冲突的,因为它们的使用场景不一样(写法也不一样)。

    因为都是表达式体形式,它们具有相同的限制:要求方法体能够改写为lambda表达式(必须是单行代码)。

    只读属性的表达式体形式(C#6)

    只读属性的表达式体形式有2个限制

    • 只包含 get访问器
    • 要求 get访问器的方法体能够改写为lambda表达式(必须是单行代码

    示例代码如下:

    //C# 5
    public string FullName
    {
        get
        {
            return FirstName + "" + LastName;
        }
    }
    
    //C# 6
    public string FullName => FirstName + "" + LastName;
    

    我们可以通过VS的智能提示看到:该属性只有get访问器。

    属性访问器的表达式体形式(C#7)

    在 C# 7.0 中,对于老式的读/写属性,我们可以把get访问器或set访问器改写为表达式体(lambda)。

    注意:要求访问器的方法体能够改写为lambda表达式(必须是单行代码

    示例代码如下:

    //C# 5
    private int _id;
    public int Id
    {
        get
        {
            return _id;
        }
        set
        {
            _id = value;
        }
    }
    
    //C# 7.0
    private int _id;
    //全部改写为表达式体
    public int Id { get => _id; set => _id = value; }
    //只改写set访问器
    public int Id { get { return _id; } set => _id = value; }
    //只改写get访问器
    public int Id { get => _id; set { _id = value; } }
    

    备注

    下面的备注,对于老式的读/写属性自动实现的属性都是通用的。

    1. 可以给访问器设置可访问性。例如把set访问器设为private,不允许外部直接赋值。通常是限制set访问器的可访问性。更多请参考:限制访问器可访问性(C# 编程指南)
    2. 可以省略掉某个访问器。通常是省略掉set访问器可使属性为只读。

    另外,属性的本质是方法,所以接口中可以包含属性

    参考

    1. 如何:声明和使用读/写属性(C# 编程指南):https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/how-to-declare-and-use-read-write-properties
    2. 自动实现的属性(C# 编程指南):https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties
    3. 限制访问器可访问性(C# 编程指南):https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/restricting-accessor-accessibility
    4. => 运算符(C# 参考):https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/operators/lambda-operator
    5. 探索C#之6.0语法糖剖析:https://www.cnblogs.com/mushroom/p/4666113.html
    6. 姜晓东《C# 4.0权威指南》-【9.4.5 属性
  • 相关阅读:
    阿里巴巴微服务开源项目盘点(持续更新)
    云计算、大数据、编程语言学习指南下载,100+技术课程免费学!这份诚意满满的新年技术大礼包,你Get了吗?
    【机器学习PAI实战】—— 玩转人工智能之综述
    泡沫下的破浪者,智能语音产品到底落地何处?
    我们总结了每个技术团队都会遇到的 4 个难题
    在 Ali Kubernetes 系统中,我们这样实践混沌工程
    云上护航服务—保障云上的尖峰时刻
    本地 vs. 云:大数据厮杀的最终幸存者会是谁?— InfoQ专访阿里云智能通用计算平台负责人关涛
    WAF开放规则定义权:专家策略+用户自定义策略=Web安全
    队列的其本应用_迷官问题
  • 原文地址:https://www.cnblogs.com/doThing/p/properties-in-csharp.html
Copyright © 2011-2022 走看看