1. 程式人生 > >【C#】詳解屬性

【C#】詳解屬性

radi 們的 cal com 位數 struct serializa 表達式 font

目錄結構:

contents structure [+]
  1. 屬性和字段的區別
  2. 無參屬性
    1. 自動實現的屬性
    2. 對象和集合初始化器
    3. 匿名類型
    4. System.Tuple類型
  3. 有參屬性
  4. 屬性的可訪問性

在這篇文章中,將會詳細介紹屬性(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"} };

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
    }
}

【C#】詳解屬性