目錄結構:
在這篇文章中,將會詳細介紹屬性(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 } }