C#3.0中定義屬性更加方便,不用再在像之前的版本那樣的繁瑣,需要先定義儲存資料的欄位,然後再定義屬性器,現在只需要定義屬性器就可以了,其它的有編譯器自動為我們完成,就可以省去定義欄位時需要的那些時間;在對象初始化的時候我們可在物件建構的時候實現對象屬性的初始化工作,和集合初始化類似。
1.匿名屬性
定義屬性如下:
public class Employee { public int Id { get; set; } public string Name { get; set; } public string Sex { get; set; } public int Age { get; set; } public string BirthDate { get; set; } }
在C#3.0 之前的寫法如下:
public class Employee { private int _id; private string _name; private string _sex; private int _age; private string _birthDate; public int Id { get { return _id; } set { _id = value; } } public string Name { get { return _name; } set { _name = value; } } public string Sex { get { return _sex; } set { _sex = value; } } public int Age { get { return _age; } set { _age = value; } } public string BirthDate { get { return _birthDate; } set { _birthDate = value; } } }
僅從代碼量上就前者比後者減少了2/3的代碼,這對提高效率是顯而易見的,那麼這些代碼都到哪裡去了呢?其實那些額外的代碼都是由編譯器為我們完成的,編譯器會將那些我們“省去"的代碼編譯成託管IL代碼的時候補進去,兩者中代碼在最終產生的IL代碼的體積是差不多的。
中的IL代碼中我們看到了 <xxx>k_BackingField之類的欄位就是編譯器自動產生的欄位代碼。
2.對象初始化器,原來的對象初始化都要進行先建立構造方法,然後才能進行成員的相關操作,C#3.0 提供了對象成員的直接初始化的能力,和初始化一個集合或者是數組一樣來初始化對象。
相面來看,通過對象初始化器對上面的的Employee類進行進行調用:
Employee employee = new Employee { Id = 1, Name = "藍之風", Age = 24, BirthDate = "1984-10-21", Sex = "男" }; Console.WriteLine("編號;{0}", employee.Id); Console.WriteLine("姓名:{0}", employee.Name); Console.WriteLine("年齡:{0}", employee.Age); Console.WriteLine("生日:{0}", employee.BirthDate); Console.WriteLine("性別:{0}", employee.Sex); Console.WriteLine("請按任意鍵繼續..."); Console.ReadLine();
這句
Employee employee = new Employee { Id = 1, Name = "藍之風", Age = 24, BirthDate = "1984-10-21", Sex = "男" };
就是對象的初始化,看到代碼很簡潔,輸出的結果如下:
在C#3.0之前的做法是:
Employee employee = new Employee(); employee.Id = 1; employee.Name = "藍之風"; employee.Age = 24; employee.BirthDate = "1984-10-21"; employee.Sex = "男"; Console.WriteLine("編號;{0}", employee.Id); Console.WriteLine("姓名:{0}", employee.Name); Console.WriteLine("年齡:{0}", employee.Age); Console.WriteLine("生日:{0}", employee.BirthDate); Console.WriteLine("性別:{0}", employee.Sex); Console.WriteLine("請按任意鍵繼續..."); Console.ReadLine();
或者通過重載構造方法的方式來初始化這些屬性,二者的達到的效果是相同的,但是前者使用起來方便了些,代碼量減少了許多,這個過程是怎麼完成的呢?其實C#本身並沒有太大的變化,這些都是在文法上的一些改變,使得編寫代碼的時候更方便效率更高,把一些編譯器可以推斷出來完成的工作讓編譯器來做了,編譯器在編譯器的時候將我們沒有實現的代碼替我們實現來產生IL代碼的:
method private hidebysig static void Main(string[] args) cil managed{ .entrypoint // 代碼大小 175 (0xaf) .maxstack 2 .locals init ([0] class CS30.Employee employee, [1] class CS30.Employee '<>g__initLocal0') IL_0000: nop IL_0001: newobj instance void CS30.Employee::.ctor() IL_0006: stloc.1 IL_0007: ldloc.1 IL_0008: ldc.i4.1 IL_0009: callvirt instance void CS30.Employee::set_Id(int32) IL_000e: nop IL_000f: ldloc.1 IL_0010: ldstr bytearray (DD 84 4B 4E CE 98 ) // ..KN.. IL_0015: callvirt instance void CS30.Employee::set_Name(string) IL_001a: nop IL_001b: ldloc.1 IL_001c: ldc.i4.s 24 IL_001e: callvirt instance void CS30.Employee::set_Age(int32) IL_0023: nop IL_0024: ldloc.1 IL_0025: ldstr "1984-10-21" IL_002a: callvirt instance void CS30.Employee::set_BirthDate(string) IL_002f: nop IL_0030: ldloc.1 IL_0031: ldstr bytearray (37 75 ) // 7u IL_0036: callvirt instance void CS30.Employee::set_Sex(string) IL_003b: nop IL_003c: ldloc.1 IL_003d: stloc.0 IL_003e: ldstr bytearray (16 7F F7 53 3B 00 7B 00 30 00 7D 00 ) // ...S;.{.0.}. IL_0043: ldloc.0 IL_0044: callvirt instance int32 CS30.Employee::get_Id() IL_0049: box [mscorlib]System.Int32 IL_004e: call void [mscorlib]System.Console::WriteLine(string, object) IL_0053: nop IL_0054: ldstr bytearray (D3 59 0D 54 3A 00 7B 00 30 00 7D 00 ) // .Y.T:.{.0.}. IL_0059: ldloc.0 IL_005a: callvirt instance string CS30.Employee::get_Name() IL_005f: call void [mscorlib]System.Console::WriteLine(string, object) IL_0064: nop IL_0065: ldstr bytearray (74 5E 84 9F 3A 00 7B 00 30 00 7D 00 ) // t^..:.{.0.}. IL_006a: ldloc.0 IL_006b: callvirt instance int32 CS30.Employee::get_Age() IL_0070: box [mscorlib]System.Int32 IL_0075: call void [mscorlib]System.Console::WriteLine(string, object) IL_007a: nop IL_007b: ldstr bytearray (1F 75 E5 65 3A 00 7B 00 30 00 7D 00 ) // .u.e:.{.0.}. IL_0080: ldloc.0 IL_0081: callvirt instance string CS30.Employee::get_BirthDate() IL_0086: call void [mscorlib]System.Console::WriteLine(string, object) IL_008b: nop IL_008c: ldstr bytearray (27 60 2B 52 3A 00 7B 00 30 00 7D 00 ) // '`+R:.{.0.}. IL_0091: ldloc.0 IL_0092: callvirt instance string CS30.Employee::get_Sex() IL_0097: call void [mscorlib]System.Console::WriteLine(string, object) IL_009c: nop IL_009d: ldstr bytearray (F7 8B 09 63 FB 4E 0F 61 2E 95 E7 7E ED 7E 2E 00 // ...c.N.a...~.~.. 2E 00 2E 00 ) // .... IL_00a2: call void [mscorlib]System.Console::WriteLine(string) IL_00a7: nop IL_00a8: call string [mscorlib]System.Console::ReadLine() IL_00ad: pop IL_00ae: ret} // end of method Program::Main從上面的IL代碼中可以清晰的看到,首先建立了Employee的執行個體,然後才對相關的屬性進行賦值操作的。
3總結:
自動屬性和對象初始化器都是C#3.0提供的文法層級的功能改進,是一種文法糖,是編寫代碼的效率更高,將一些重複性的工作交給編譯器來做,但是這種改變,也增加了代碼的不透明性,這點在隱式類型中體現的更為突出,增加了代碼理解的難度,這些僅僅是提供給代碼編寫人員的一種選擇,如果不喜歡也可以按照原來的方式來書寫自己的代碼也未嘗不可。