zoukankan      html  css  js  c++  java
  • 【C#】C#中的属性与字段

    目录结构:

    contents structure [+]

    在这篇文章中,将会详细介绍属性(Property)。属性总的分为两种,一种是有参属性(索引器),另一种是无参属性。

    1.属性和字段的区别

    属性(Property)和字段(Field)想必读者都是见到过的,他们的区别见如下代码:

        class Person {
            public String m_name;//字段
            public Int32 m_age;
    
            public String Name{//属性
                get { return m_name; }
                set { m_name = value; }//关键字value代表新值
            }
            public Int32 Age {
                get {return m_age;}
                set {m_age = value;}
            }
        }

    从上面的定义的Person类可以看出,通常,封装了字段访问的方法就是访问器(属性)。严格的说,属性是方法。

    2.无参属性

    无参属性就是如同上面的Person类中的属性,无索引器。

    2.1 自动实现的属性

    C#为无参属性提供了一种更简便的语法,称为自动实现属性(Automatically Implemented Property 简称为API)。
    例如:

        class Person {
            public String Name{set;get;}
            public Int32 Age{get;set;}
        }

    上面C#会自动为Name和Age属性声明字段,并且也会自动实现Name和Age属性的主体方法,分别设置和返回字段中的值。

    2.2 对象和集合初始化器

    经常要构造一个对象,并设置对象的一些公共属性(或字段),C#简化了这个常见的编程模式。
    还是以上面的Person类举例,在有了Person类中,我们就可以声明对象和初始化值一步完成(通过无参构造器):

    Person person = new Person() { Name="jame",Age=12};

    如果属性实现了IEnumerable或是IEnumerable<T>接口,那么属性就会被认为是集合,例如:

        class Classroom {
            public List<String> Student { set; get; }
        }

    然后可以就使用如下的代码完成创建Classroom对象并且初始化Student属性值。

    Classroom classroom = new Classroom() { Student = { "green","red","blue"} };

    知道了上面的知识后,我们就可以创建集合对象与赋值一步完成,例如:

    List list=new List<String>{"a","b"};

    2.3 匿名类型

    C#可以利用匿名类型来声明不可变(immutable)的元组类型。一旦类型声明完成后,就不可以更改。
    例如:

    var o1 = new {Name="jame",Age=12,Sex="" };
    //o1.Name = "231";//编译不通过,因为Name是只读属性。
    Console.WriteLine(o1.Name);//jame
    Console.WriteLine(o1.Age);//12
    Console.WriteLine(o1.Sex);//

    上面的代码,C#自动创建一个匿名类型,并且含有Name、Age、Sex的只读属性。

    通过上面的代码可以看出,C#提供匿名类型的语法是:

    var o=new {perperty1=expression1,...,perpertyN=expressionN};

    C#会推断每个表达式的类型,并且创建类型的私有字段,为每个字段创建公共只读属性,并且创建一个构造器来接受所有这些表达式。

    2.4 System.Tuple类型

    这里介绍一下System.Tuple类型,因为System.Tuple类型中的所有属性都是只读的。System.Tuple有好几个泛型版本,区别在于他们的元数(泛型参数的个数)。

    //最简单的泛型Tuple类型
    [Serializable]
    public class Tuple<T1>{
        private readonly T1 m_Item1;
        public T1 Item1 { get { return m_Item1; } }
        public Tuple(T1 item1) {
            m_Item1 = item1;
        }
    }
    //最复杂的泛型Tuple泛型类型
    [Serializable]
    public class Tuple<T1, T2, T3, T4, T5, T6, T7, TRest>{
     
            private readonly T1 m_Item1;
            private readonly T2 m_Item2;
            private readonly T3 m_Item3;
            private readonly T4 m_Item4;
            private readonly T5 m_Item5;
            private readonly T6 m_Item6;
            private readonly T7 m_Item7;
            private readonly TRest m_Rest;
     
            public T1 Item1 { get { return m_Item1; } }
            public T2 Item2 { get { return m_Item2; } }
            public T3 Item3 { get { return m_Item3; } }
            public T4 Item4 { get { return m_Item4; } }
            public T5 Item5 { get { return m_Item5; } }
            public T6 Item6 { get { return m_Item6; } }
            public T7 Item7 { get { return m_Item7; } }
            public TRest Rest { get { return m_Rest; } }
     
            public Tuple(T1 item1, T2 item2, T3 item3, T4 item4, T5 item5, T6 item6, T7 item7, TRest rest) {
                m_Item1 = item1;
                m_Item2 = item2;
                m_Item3 = item3;
                m_Item4 = item4;
                m_Item5 = item5;
                m_Item6 = item6;
                m_Item7 = item7;
                m_Rest = rest;
            }
    }

    Tuple类从System.Object派生,并且实现了IStructuralEquatable, IStructuralComparable接口,它们的是可比较的。
    栗子:

    static void Main(string[] args)
    {
        Tuple<Int32, Int32> vals = MinMax(12,21);
        Console.WriteLine(vals.Item1);//12
        Console.WriteLine(vals.Item2);//21
        Console.ReadLine();
    
    }
    static Tuple<Int32, Int32> MinMax(Int32 a, Int32 b) {
        return new Tuple<int, int>(Math.Min(a,b),Math.Max(a,b));
    }

    3.有参属性

    我们将属性的get访问器是否能接受参数,分为无参属性和有参数属性(索引器)。

    CLR本身是不区分有参属性和无参属性的。对CLR来说,每个属性只是类型定义的一对方法和元数据。不同的编程语言使用使用了不同的语法来创建有参属性,C#使用this[...]作为表达器索引的语法,因此C#只支持在对象的实例上定义索引器。
    例如:

    class BitArray {
        private Byte[] m_byteArray;
        private Int32 m_numBits;
    
        public BitArray(Int32 numBits) {
            //验证实参
            if (numBits <= 0)
                throw new ArgumentException("numBits must be > 0");
            //保存位的个数
            m_numBits = numBits;
            //为位分配字节
            m_byteArray=new Byte[(numBits+7)/8];//之所以要加7,因为即使位数小于8,也应该有一个字节。
        }
        //下面是索引器(有参属性)
        public Boolean this[Int32 bitPos] {
            get {
                if (bitPos < 0 || bitPos >= m_numBits) {
                    throw new ArgumentException("bitPos");
                }
                return (m_byteArray[bitPos/8]&(1<<(bitPos%8)))!=0;//判断下标(bitPos%8)位的值是否不是0
            }
            set {
                if (bitPos < 0 || bitPos >= m_numBits)
                {
                    throw new ArgumentException("bitPos");
                }
                if (value)
                {
                    //将指定索引处的位设置为true
                    m_byteArray[bitPos / 8] = (Byte)(m_byteArray[bitPos / 8] | (1 << (bitPos % 8)));//将下标(bitPos%8)位的值设置为1
                }
                else {
                    //将指定索引处的位设置为false
                    m_byteArray[bitPos / 8] = (Byte)(m_byteArray[bitPos / 8] & ~(1 << (bitPos % 8)));//将下标(bitPos%8)的位的值设置0
                }
            }
        }
    }

    然后就可以像如下这样来使用BitArray的索引器了。

    BitArray ba = new BitArray(14);
    //调用set访问器,将所有偶数位都设置为true
    for (Int32 x = 0; x < 14; x++) {
        ba[x]=(x%2==0);
    }
    //调用get访问器,显示所有位的状态。
    for (Int32 x = 0; x < 14; x++) {
        Console.WriteLine("Bit "+x+" is "+(ba[x]?"On":"Off"));
    }

    4.属性的可访问性

    有时希望为get访问器方法提供一个可访问性,为set访问器方法指定另一种可访问器。
    例如:

    public class SomeType{
        private String m_name;
        public String Name{
            get{return m_name;}//默认
            protected set{m_name=value;}//指定为protected
        }
    }
  • 相关阅读:
    tail命令语法
    正则表达式示例
    HTTP状态码对照表 HTTP response codes
    linux 源的配置更新
    shell基本语法
    谁偷走了程序员的时间??
    Spring Data JPA 简单查询-接口方法
    GET和POST两种基本请求方法的区别
    您是怎样度过人生的低潮期的
    树莓派中Docker部署.Net Core 3.1 (一)
  • 原文地址:https://www.cnblogs.com/HDK2016/p/9461099.html
Copyright © 2011-2022 走看看