寫在前邊:
做事不堅持,是我這麼多年來最失敗的地方,從今天開始改正,沒有人也沒有動力督促,只能靠自己的決心和行動,來證明...。今天來學學自動屬性,初始值設定項,或叫初始化器。本人知道,這樣的內容在網上早有了,不知能不能放首頁。再放一次,聽聽前輩同仁們的意見。
一、自動屬性:
在C# 2.0中,我們對成員進行封裝,也就是自動屬性,如下示例:
private int m_one;
public int One
{
get { return m_one; }
set { m_one = value; }
}
這種方式只需寫第一句代碼,然後用Visual Studio的Refactor->Encapsulate Field功能,很方便,也早已經為大家熟知。而在C# 3.0中,我們只需要寫成如下一句就可以了:
public int Dne { get; set; }// Auto-implemented properties
可以看出,C# 3.0中這種自動屬性對C# 2.0中的屬性寫法作了大大的簡化。C# 3.0的自動屬性就不需要創建私有變量,而把這個工作交給編譯器代勞!當然,如果需要在獲取訪問器get或設置訪問器set裡頭添加一些邏輯,擴展也很方便。
二、對象初始值設定項
使用對象初始值設定項可以在創建對象時向對象的任何可訪問的字段或屬性分配值,而無需顯式調用構造函數。對象初始值設定項,我在很多地方看到,其名稱,又叫對象初始化器。看實例,以前,我們首先定義一個類:
public class MyClass
{
public string Number { get; set; }
public string Name { get; set; }
public MyClass()
{
}
public MyClass(string newID)
{
Number = newID;
}
public MyClass(string newID, string newName)
{
Number = newID;
Name = newName;
}
}
然後,new一個對象,並對其屬性初始化:
public static void newObject()
{
MyClass cobject = new MyClass();
cobject.Name = "yy";
cobject.Number = "1111";
MyClass dobject = new MyClass("1111");
dobject.Name = "yy";
MyClass eobject = new MyClass("1111","yy");
}
現在,在C# 3.0中,利用對象初始化器,new一個對象,並對可以訪問的屬性初始化,只需要如下一句代碼:
MyClass nobject = new MyClass{Name = "yy",Number = "1111"};
從本質上講,對象初始化器只是簡化了代碼編寫工作,後台編譯器自動完成轉換。對象初始化器實際上利用了編譯器對對象中對外可見的字段和屬性進行按序賦值,在編譯時還是隱式調用了構造函數,對字段或屬性的進行逐一賦值。如果一個類的成員又是一個類,仍舊可以用象初始化器設置更復雜的嵌套(nested)屬性類型。如把MyClass再加一個屬性:
public OClass oclassMember { get; set; }
該屬性的類的定義如下:
public class OClass
{
public string addr { get; set; }
public string zip { get; set; }
public OClass()
{
}
public OClass(string address, string zipCode)
{
this.addr = address;
this.zip = zipCode;
}
}
然後,在newObject方法中,new一個新對象完全可以這樣做:
MyClass nestobject = new MyClass
{
Name = "yy",
Number = "1111",
oclassMember = new OClass
{
addr = "neijiang",
zip = "404045"
}
};
使用了這麼多,需要注意的也還是有:
自動屬性中,get和set後都有分號,花括號後邊沒有,二在對象初始化器的使用中,花括號中對各個屬性賦值時用逗號隔開,花括號結束了用分號。本質原因,自動屬性是屬性定義,按C# 2.0語法,get和set分別相當於一個語句,花括號相當於方法的開始和結束。而使用對象初始化器,相當於使用花括號來調用其構造函數,整個new的過程相當於一條語句。
在使用對象初始化器設置嵌套的屬性類型的時候,內層嵌套的屬性用對象初始化器後的花括號後也是用逗號,而不是用分號。如果這嵌套的屬性放在了最後,則不用,如上例。
不管是嵌套的屬性,或者不嵌套的屬性,或者被嵌套的屬性,使用對象初始化器,要去該對象所屬的類必須提供沒有參數的構造函數,否則會報錯:does not contain a constructor that takes '0' arguments。
使用對象初始化器時,花括號中對屬性賦值的順序可以交換,如:
MyClass nestobject1 = new MyClass
{
Name = "yy",
oclassMember = new OClass
{
addr = "neijiang",
zip = "404045"
},
Number = "1111"
};
也是對的。
三、將對象初始值設定項用於匿名類型
查詢表達式經常使用匿名類型,而這些類型只能使用對象初始值設定項進行初始化。如:
MyClass[] ojbset = new MyClass[12];
var vaobj =
from obj in ojbset
select new { obj.Name, obj.Number };
也就是說,把objset中的每一個obj的Name屬性和Number屬性拿來,new成新隱式類型,賦值給vaobj,這種新類型的屬性名也被省略掉了,那實際上,其屬性名就是Name和Nnumber,值分別是它們兩者的值。這個方式呢,由於new { obj.Name,obj.Number };這句是new的一個新的隱式類型,與類MyClass沒有關系,所以,MyClass沒有無參構造函數也是可以的。而如果要在new隱式類型的時候,重新命名其屬性,則可以采用如下方式:
var varobj =
from vobj in ojbset
select new { vobj.Name, ID = vobj.Number };
四、集合初始值設定項
集合初始值設定項,也叫集合初始化器,會對初始化器中的元素進行按序調用ICollection<T>.Add(T) 。使用集合初始值設定項的對象的類型必須實現了System.Collections.Generic.ICollections<T>接口並指定了確定的T。使用它可以在初始化一個實現了IEnumerable的集合類時指定一個或多個元素初始值;
元素初始值設定項可以是簡單的值,也可以是表達式或對象初始值設定項;
通過使用集合初始值設定項,無需在源代碼中指定多個對該類的Add 方法的調用;編譯器會添加這些調用。
例子如下:
public void setinit()
{
List<int> digits = new List<int> {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
};
List<int> digits2 = new List<int> {
0 + 1, 12 % 3, getIntNumber()
};
List<MyClass> customers = new List<MyClass>{
new MyClass{Number="1111",Name="yy"},
new MyClass{Number="2222",Name="qq"},
new MyClass{Number="3333",Name="qiqi"}
};
}
public int getIntNumber()
{
return 56;
}
這和以前調用List.Add沒有本質的區別,編譯器自動的調用了List的無參構造方法,然後實例化一個個的MyClass,再一個個的Add進去,和我們原來的做法沒有什麼不同,但是,這是編譯器在後台自動處理,簡省了我們很多的編碼工作。
注:
各項之間還是用逗號,結束了,花括號後邊表示new這個集合結束,用分號。
如果集合的Add 方法允許,可以將null 指定為集合初始值設定項中的一個元素。如:
List<MyClass> customers = new List<MyClass>{
new MyClass{Number="1111",Name="yy"},
new MyClass{Number="2222",Name="qq"},
new MyClass{Number="3333",Name="qiqi"},
null
};
五、總結
這些新特性平常怕是很少用到的,因為已經習慣了C# 2.0的寫法,而且,這樣寫又不是必須的。但真正熟悉了,編譯器已經幫開發人員做了越類越多的工作,從而節約了我們的開發時間。或許,在其它的應用當中,這樣的語法還能用的到吧。