zoukankan      html  css  js  c++  java
  • 属性,属性

    无参属性


      属性是类或对象中的一种智能字段形式。从对象外部,它们看起来像对象中的字段。 如下定义了一个属性Name,属性包含get和set访问器的声明。

    public class Person
    {
        private string name;
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }
    

    为什么不直接使用类型的成员字段?

    面向对象设计和编程的重要原则之一就是数据封装,类型的字段不应该公开,否则很容易因为不恰当使用字段而破坏对
    象的状态。所以应提供公有的方法访问私有的字段,封装了字段访问的方法通常叫做访问器方法,访问器方法可以
    对数据的合理性进行检查,确保对象的状态永远不被破坏。

    下面,通过查看ildasm工具,了解编译器在定义属性时做了哪些工作。

    如上图所示,编译器生成了get和set访问器方法,并且在属性名之前自动附加了get_和set_前缀来命名方法。除此之外,还生成了一个属性的定义项(IL代码如下),在这个记录项中包含了一些flag、属性的类型以及对get和set访问器方法的引用,这些元数据信息可供编译器和其他工具使用。

    .property instance string Name()
    {
        .get instance string Property.Person::get_Name()
        .set instance void Property.Person::set_Name(string)
    } // end of property Person::Name
    

    自动属性

      如果只是为了封装一个支持字段而创建属性,C#提供了自动实现的属性(Automatically Implemented Property,AIP),语法如下,也可以键入prop+两个tab键快速生成自动属性

        public string Name { get; set; }
    

    编译器会自动声明一个string类型的私有字段,并实现get_Name和set_Name方法。注意:使用AIP,属性是可读可写的。另外,如果需要显示实现get或set访问器方法,就必须同时显示实现。在C#6和更高版本,可以像字段一样初始化自动实现属性。

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

    对象和集合初始化器

      一般要构造一个新对象并设置对象的一些公共属性的代码如下:

    class Program
    {
        static void Main(string[] args)
        {
            Person person = new Person();
            person.Name = "Mike";
            person.Age = 24;
        }
    }
    
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
    

    为了简化这个常见的编程模型,C#提供了一种简单的初始化语法:

    Person person = new Person { Name = "Mike", Age = 24 };
    

    由于调用的是Person类的无参构造函数,这里省略了小括号,并在语句的结尾处的大括号内设置了person对象的Name和Age属性。

    如果属性的类型实现了IEnumerable或IEnumerable<T>接口,属性就被认作是集合,为Person类添加Hobbies属性。

    private List<string> hobbies = new List<string>();
    public List<string> Hobbies
    {
        get { return hobbies; }
        set { hobbies = value; }
    }
    

    构造Person对象,设置Name、Age和Hobbies属性:

    Person person = new Person { Name = "Mike", Age = 24, Hobbies = { "reading", "swimming" } };
    

    编译上述代码时,编译器发现Hobbies属性的类型是List<string>,该类型实现了IEnumerable<string>接口,然后生成代码来调用集合的Add方法。因此,上述代码会转换成:

    Person person = new Person();
    person.Name = "Mike";
    person.Age = 24;
    person.Hobbies.Add("reading");
    person.Hobbies.Add("swimming");
    

    匿名类型

      使用C#的匿名类型,可以用简洁的语法来声明类型,如上节中定义的Person类型,可以使用如下代码:

     var person = new { Name = "Mike", Age = 24, Hobbies = new List<string>() { "reading", "swimming" } };
    

    下面通过ildasm工具查看这段程序的元数据信息,看看编译器都做了什么。

    编译器会推断出每个表达式的类型,创建私有字段,为每个字段创建公共只读属性,并创建一个构造函数来接受这些表达式,在构造函数代码中(IL代码如下),会用传入表达式的求值结果来初始化私有的只读字段。除此之外,编译器还会重写Object类的Equals、GetHashCode和ToString方法。

    .method public hidebysig specialname rtspecialname 
            instance void  .ctor(!'<Name>j__TPar' Name,
                                !'<Age>j__TPar' Age,
                                !'<Hobbies>j__TPar' Hobbies) cil managed
    {
    .custom instance void [mscorlib]System.Diagnostics.DebuggerHiddenAttribute::.ctor() = ( 01 00 00 00 ) 
    // Code size       28 (0x1c)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ldarg.0
    IL_0007:  ldarg.1
    IL_0008:  stfld      !0 class '<>f__AnonymousType0`3'<!'<Name>j__TPar',!'<Age>j__TPar',!'<Hobbies>j__TPar'>::'<Name>i__Field'
    IL_000d:  ldarg.0
    IL_000e:  ldarg.2
    IL_000f:  stfld      !1 class '<>f__AnonymousType0`3'<!'<Name>j__TPar',!'<Age>j__TPar',!'<Hobbies>j__TPar'>::'<Age>i__Field'
    IL_0014:  ldarg.0
    IL_0015:  ldarg.3
    IL_0016:  stfld      !2 class '<>f__AnonymousType0`3'<!'<Name>j__TPar',!'<Age>j__TPar',!'<Hobbies>j__TPar'>::'<Hobbies>i__Field'
    IL_001b:  ret
    } // end of method '<>f__AnonymousType0`3'::.ctor
    

    到这里我们已经大概了解了匿名类型的使用方法,下面请看这段代码:

    var mike = new { Name = "Mike", Age = 24, Hobbies = new List<string>() { "reading", "swimming" } };
    var jack = new { Name = "Jack", Age = 31, Hobbies = new List<string>() { "coding", "playing basketball" } };
    

    那么问题来了,这段代码究竟会生成几个类呢?查看元数据信息,答案是一个。看来编译器还是很智能的,对于具有相同结构的匿名类型,只会创建一个类型的定义。这时我们再来做个试验,把Name和Age的属性调换一下位置。

    var mike = new { Name = "Mike", Age = 24, Hobbies = new List<string>() { "reading", "swimming" } };
    var jack = new { Age = 31, Name = "Jack", Hobbies = new List<string>() { "coding", "playing basketball" } };
    

    编译后再次查看元数据,发现这时生成了两个类型的定义。

    结论:当定义多个匿名类型时,如果每个属性都有相同的类型和名称,并且这些属性指定的顺序完全相同,那么它只会创建一个匿名类型的定义。

    由于编译器还有这种操作,为我们使用匿名类型定义一组对象构成集合提供了可能性,没错,我说的就是配合LINQ的select操作符构建对象的集合,示例如下:

    class Employee
    {
        public string EmployeeId { get; private set; }
        public string EmployeeName { get; private set; }
        public int DepartmentId { get; private set; }
        public int Age { get; private set; }
        public int Salary { get; private set; }
    
        public Employee(string employeeId, string employeeName, int departmentId, int age, int salary)
        {
            this.EmployeeId = employeeId;
            this.EmployeeName = employeeName;
            this.DepartmentId = departmentId;
            this.Age = age;
            this.Salary = salary;
        }
    }
    
    class Department
    {
        public int DepartmentId { get; private set; }
        public string DepartmentName { get; private set; }
        public Department(int departmentId, string departmentName)
        {
            this.DepartmentId = departmentId;
            this.DepartmentName = departmentName;
        }
    }
    
    static void Main(string[] args)
    {
        List<Employee> employees = new List<Employee>
        {
            new Employee("001","Mike",2,24,30000),
            new Employee("002","Jack",1,34,40998),
            new Employee("003","Altony",2,26,58888),
            new Employee("004","Carl",3,32,350000),
            new Employee("005","Duncan",1,34,100000)
        };
    
        List<Department> departments = new List<Department>
        {
            new Department(1,"HR"),
            new Department(2,"IT"),
            new Department(3,"FT"),
        };
    
        var query = from q in employees
                    join t in departments on q.DepartmentId equals t.DepartmentId
                    where q.Age > 30
                    select new
                    {
                        Name = q.EmployeeName, Age = q.Age, DepartmentName = t.DepartmentName
                    };  //匿名类型的对象构成的集合
    
        foreach (var employee in query)
        {
            Console.WriteLine($"EmployeeName= {employee.Name},Age={employee.Age},DepartmentName={employee.DepartmentName}");
        }
    
        Console.ReadLine();
    }
    

    有参属性


      上一节中,属性的get访问器方法不接受参数,因此称为无参属性。除此之外,C#还支持有参属性(也称为索引器)。

    class SampleCollection
    {
        private int[] arr = new int[10];
        public int this[int i]
        {
            get
            {
                return arr[i] * 100 + 300;
            }
            set
            {
                arr[i] = value;
            }
        }
    }
    
     static void Main(string[] args)
     {
        SampleCollection sample = new SampleCollection();
        sample[0] = 100;
        Console.WriteLine(sample[0]);   //Output:10300
        Console.ReadLine();
    }
    

    根据以上示例,能够看出:

    1. 和无参属性类似,索引器也需要定义get,set访问器,并且在set访问器中可以使用value关键字。
    2. 索引器的get访问器需要接受参数。
    3. 使用this关键字定义索引器。

    老样子,查看程序集元数据信息。

    编译器生成的get/set访问器方法的默认名称为get/set_Item,C#允许向索引器应用定制特性来重命名这些方法。

    class SampleCollection
    {
        private int[] arr = new int[10];
        [System.Runtime.CompilerServices.IndexerName("Answer")]
        public int this[int i]
        {
            get
            {
                return arr[i] * 100 + 300;
            }
            set
            {
                arr[i] = value;
            }
        }
    }
    

  • 相关阅读:
    Leetcode: Find Median from Data Stream
    Leetcode: Flip Game II
    Leetcode: Flip Game
    Leetcode: Nim Game
    Leetcode: Word Pattern II
    Leetcode: Word Pattern
    Leetcode: Game of Life
    Leetcode: Alien Dictionary && Summary: Topological Sort
    Leetcode: Unique Word Abbreviation
    Leetcode: Find the Duplicate Number
  • 原文地址:https://www.cnblogs.com/Answer-Geng/p/7570187.html
Copyright © 2011-2022 走看看