• C#基础 [09] 属性


    一、属性的定义和特征

      1.属性的定义

        属性是表示类或类的实例中的一个数据项的成员:它提供灵活的机制来读取、编写或计算某个私有字段的值。可以像使用公共数据成员一样使用属性,但实际上它们是称作“访问器”的特殊方法。这使得可以轻松访问数据,此外还有助于提高方法的安全性和灵活性。

      2.属性的特征

        1).属性是命名的类成员,它有类型,可以被赋值和读取。

        2).与字段不同,属性是一个函数成员;它本身没有任何存储,不为数据存储分配内存;它执行代码。

        3).属性有两个匹配的、称为访问器的方法:set访问器为属性赋值,get访问器从属性中获取值。

        4).在使用属性时,属性访问器被隐式调用:当为属性赋值时,set访问器被隐式调用;当从属性中读取值时,get访问器被隐式调用;不能显式调用访问器。

      3.属性的示例   

    View Code
     1     class TimePeriod
     2     {
     3         // 声明一个后备字段
     4         private double seconds;
     5 
     6         // 声明一个doub类型的属性,在属性内部将小时转换为秒
     7         public double Hours
     8         {
     9             // get访问器:返回属性类型的值
    10             get { return seconds / 3600; }
    11             // set访问器:为属性赋值
    12             set { seconds = value * 3600; }
    13         }
    14     }    
    15 
    16     class Program
    17     {
    18         static void Main(string[] args)
    19         {
    20             TimePeriod t = new TimePeriod();
    21 
    22             // 为属性赋值,隐式调用set访问器.
    23             t.Hours = 24;
    24 
    25             // 读取属性值,隐式调用get访问器.
    26             System.Console.WriteLine("Time in hours: " + t.Hours);
    27         }
    28     }

    二、属性访问器

      属性的访问器就是两个方法,set访问器和get访问器有预定义的语法和语义。我们按照预定义的语法声明的属性,经过编译器编译之后,会自动分别为set访问器和get访问器生成相应的方法。编译器生成的方法经过反编译可以看得一清二楚。下面是我用Reflector反编译上例中的TimePeriod类之后,它的Hours属性的结构:

      可以看到,编译器为Hours属性生成了一个返回值类型为void的方法名为set_Hours的方法,一个返回值类型为double的get_Hours方法。

      1.set访问器

        从上图已经可以看到了属性内部的结构。这里再来进一步分析属性所生成的setHours方法内部的秘密。经过反编译之后的set_Hours方法的内部代码如下:

    1 public void set_Hours(double value)
    2 {
    3     this.seconds = value * 3600.0;
    4 }

        从上面代码中我们可以分析得出set访问器的特征:

          1).set访问器有一个单独的、隐式的值参数,参数名称为value,参数类型与属性的类型相同。

          2).set访问器的返回类型为void。

      2.get访问器

        下面是get_Hours方法的内部实现代码:

    1 public double get_Hours()
    2 {
    3     return (this.seconds / 3600.0);
    4 }

        get访问器的特征:

          1).get访问器没有参数。

          2).get访问器有一个与属性类型一致的返回值类型。

          3).get访问器的所有执行路径必须有一条return语句,返回属性类型的值。

    三、属性和关联字段

      1.属性通常和字段关联,字段存储实际的数据,而属性为字段提供了一种访问渠道。通常的做法是:在类中将字段声明为private,并且为字段声明一个public属性以提供受控的从类的外部对字段的访问。和属性关联的字段称为“后备字段"。

      2.属性和后备字段有两种命名约定:

        第一种:后备字段采用camel命名法,而属性采用字段的Pascal命名版本。

        第二种:属性命名不变,仍然使用Pascal命名法,字段采用"下划线+camel"的形式。

       3.下面是另一个示例:该示例声明了一个名为Student的类,该类的每个属性都有一个采用了“_+camel”命名的后备字段。其中类成员声明按照:Fields—>Methods->Properties的顺序进行。

    View Code
     1 using System;
     2 namespace MyClass
     3 {
     4     class Student
     5     {
     6         // Fields
     7         private string _name;
     8         private string _sex;
     9         private int _age;
    10         private float _chinese;
    11         private float _math;
    12         private float _english;
    13 
    14         // Constructor
    15         public Student()
    16         {
    17 
    18         }
    19 
    20         // Methods
    21         public void SayHello()
    22         {
    23             System.Console.WriteLine("我叫{0},今年{1}岁了,是{2}同学", this.Name, this.Age, this.Sex);
    24         }
    25         
    26         /// <summary>
    27         /// 总成绩
    28         /// </summary>
    29         /// <returns></returns>
    30         public float Sum()
    31         {
    32             return this.Chinese + this.Math + this.English;
    33         }
    34 
    35         /// <summary>
    36         /// 平均成绩
    37         /// </summary>
    38         /// <returns></returns>
    39         public float Average()
    40         {
    41             return (this.Chinese + this.Math + this.English) / 3f;
    42         }
    43 
    44         // Properties
    45         public string Name
    46         {
    47             get { return this._name; }
    48             set { this._name = value; }
    49         }
    50 
    51         public string Sex
    52         {
    53             get { return _sex; }
    54             set { _sex = value; }
    55         }
    56 
    57         public int Age
    58         {
    59             get { return _age; }
    60             set { _age = value; }
    61         }
    62 
    63         public float Chinese
    64         {
    65             get { return _chinese; }
    66             set { _chinese = value; }
    67         }
    68 
    69         public float Math
    70         {
    71             get { return _math; }
    72             set { _math = value; }
    73         }
    74 
    75         public float English
    76         {
    77             get { return _english; }
    78             set { _english = value; }
    79         }
    80     }
    81 }

    四、只读属性和只写属性

      1.只读属性:只有get访问器的属性称为只读属性。该属性使得只能将一项数据从类或类的实例传出,而不能有其它访问。

            public string Name
            {
                get { return this._name; }             
            }

      2.只写属性:只有set访问器的属性称为只写属性。该属性值允许数据从类的外部传入类。

    1         public string Name
    2         {
    3             set { this._name = value; }
    4         }

      3.属性必须有至少一个访问器,要么既可读、又可写,要么提供一个。不然编译器会报错。下面是我将Name属性的set访问器和get访问器都去掉之后报的一条错误消息:

    五、属性与公共字段的比较

      属性结合了字段和方法的多个方面。对于对象,属性显示为字段,访问属性需要与访问字段相同的语法。对于类的实现者(类本身),属性是一个或两个代码块,表示一个 get 访问器和/或一个 set 访问器。访问器可以对数据的访问提供一些限制和流程控制。

      以下两点表明在实际编码中使用属性更好、更灵活:

        1.字段是数据成员,只有存储能力,没有处理数据能力;而属性是函数成员,可以通过访问器对数据的输入输出进行控制。

        2.程序编译之后,字段和属性的语义不同。

    六、自动实现属性

      1.从C#3.0中增加了自动实现属性(automatically implemented property),自动属性就是只声明属性而不声明后备字段,编译器会自动创建隐式的后备字段,并且自动与set和get访问器相关联。当属性的访问器中不需要其他逻辑时,自动实现的属性可使属性声明更加简洁。实际开发中,很多都是使用自动属性的。

      2.自动实现属性的特征:

        1).不必声明后备字段,编译器会根据属性的类型自动生成隐式的后备字段来存储数据。

        2).不能提供访问器的方法体,set访问器和get访问器的方法体被一个分号代替。这也是符合逻辑的,因为都不知道后备字段是什么,当然无法对它提供访问控制了,这一切都交给了编译器。

        3).必须同时提供读写属性,缺一不可。

      3.示例

    1         // 自动实现属性
    2         public string Name
    3         {
    4             // 只有简单的get;和set;没有提供方法体
    5             get;
    6             set;
    7         }

      4.自动实现属性的内部实现

    View Code
     1 // 由编译器生成的set访问器
     2 [CompilerGenerated]
     3 public void set_Name(string value)
     4 {
     5     this.<Name>k__BackingField = value;
     6 }
     7 
     8 // 编译器生成的get访问器
     9 [CompilerGenerated]
    10 public string get_Name()
    11 {
    12     return this.<Name>k__BackingField;
    13 }

      通过上面的代码可以看出,编译器为自动属性Name生成了名为“”的后备字段,并且生成了set_Name和get_Name两个访问器。

    七、静态属性

      1.静态属性与声明方式

        可以在属性声明的类型前面加上static关键字声明静态属性。静态属性的特征如下:

          1).不能访问类的实例成员。

          2).不管类是否有实例,静态属性都是存在的。

          3).访问方式:从类的内部访问时,与访问其他类成员一样;从类的外部访问时,需要使用“类型名.成员名”的方式。

      2.示例

    View Code
     1     class Trivial
     2     {
     3         // 声明一个静态自动实现属性
     4         public static int MyVale { get; set; }
     5 
     6         // 声明一个实例方法
     7         public void PrintValue()
     8         {
     9             // 从类内部的实例方法访问静态属性:与访问其他成员一样。
    10             Console.WriteLine("MyValue = {0}", MyVale);
    11         }
    12     }
    13     class Program
    14     {
    15         static void Main(string[] args)
    16         {
    17             #region MyRegion
    18             TimePeriod t = new TimePeriod();
    19 
    20             // 为属性赋值,隐式调用set访问器.
    21             t.Hours = 24;
    22 
    23             // 读取属性值,隐式调用get访问器.
    24             System.Console.WriteLine("Time in hours: " + t.Hours); 
    25             #endregion
    26 
    27             // 从类的外部访问静态属性:使用"类名.属性名"的访问方式
    28             Trivial.MyVale = 10;
    29             Console.WriteLine(Trivial.MyVale);
    30         }
    31     }
  • 相关阅读:
    excel中年月日格式的数据分离出年
    Vision MLP 之 Sparse-MLP A Fully-MLP Architecture with Conditional Computation
    Vision MLP 之 S2-MLP V1&V2 : Spatial-Shift MLP Architecture for Vision
    Visoin MLP之CycleMLP A MLP-like Architecture for Dense Prediction
    Vision MLP之RaftMLP Do MLP-based Models Dream of Winning Over Computer Vision
    Vision MLP之Hire-MLP: Vision MLP via Hierarchical Rearrangement
    显著性目标检测之Learning to Promote Saliency Detectors
    paddle中的LoDTensor
    C语言0长度数组(可变数组/柔性数组)
    1、迭代器失效
  • 原文地址:https://www.cnblogs.com/sunyunh/p/2841692.html
Copyright © 2020-2023  润新知