程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 理解隱式類型、對象初始化程序和匿名類型

理解隱式類型、對象初始化程序和匿名類型

編輯:C#入門知識

理解隱式類型、對象初始化程序和匿名類型


在C# 3.0中,幾乎每個新特性都是為LINQ服務的。所以,本文將介紹下面幾個在C# 3.0中引入的新特性:   自動實現的屬性 隱式類型的局部變量 對象和集合初始化程序 隱式類型的數組 匿名類型 其實這幾個特性都是比較容易理解的,對於這幾個特性,編譯器幫我們做了更多的事情(想想匿名方法和迭代器塊),從而簡化我們的代碼。   自動實現的屬性 在C# 3.0以前,當我們定義屬性的時候,一般使用下面的代碼     public class Book {     private int _id;     private string _title;       public int Id     {         get { return _id; }         set { _id = value; }     }       public string Title     {         get { return _title; }         set { _title = value; }     } }   在C# 3.0中引入了自動實現的屬性,編譯器會幫我們做更多的轉換,所以我們可以把上面的屬性實現代碼轉換為:   public class Book {     public int Id { get; set; }     public string Title { get; set; } } 在使用了自動實現的屬性之後,代碼變短了,我們也沒有必要再定義私有的字段。   其實,當查看過IL代碼之後就會發現這裡編譯器幫我們定義了私有字段,實現了get/set方法。       注意,當使用結構的時候,如果要使用自動屬性,會有一個小問題:所有的構造函數都需要顯式地調用無參數的構造函數this(),只有這樣,編譯器才知道所有的字段都被明確的賦值了。   例如下面代碼中,當我們刪除":this()"後,編譯器就會報錯。   public struct Student {     public int Id { get; set; }     public string Name { get; set; }     public string Gender { get; set; }       //在結構中使用自動屬性一定要顯式地調用無參數的構造函數this()     public Student(string name):this()     {         this.Name = name;     } }   隱式類型的局部變量 C# 1.0和C# 2.0中的類型系統是靜態、顯示和安全的。   在C# 3.0中我們可以使用var關鍵字定義隱式類型的變量,但是變量仍然是靜態類型,只是編譯器可以幫助我們推斷變量的類型。   下面看一段代碼,使用隱式類型的語句跟注釋掉的語句的IL代碼是相同的:     static void Main(string[] args) {     var str = "hello world";//string str = "hello world";     var num = 9;// int num = 9;       Console.WriteLine(str.GetType());     Console.WriteLine(num.GetType());     Console.Read(); }       通過代碼的輸出可以看到,每個隱式類型的變量都是靜態類型(同樣我們也可以通過VS單步調試來查看隱式類型變量的類型),在這裡是編譯器幫我們做了類型推斷。   為了驗證這一點,但我們給str變量賦一個整型的值時,就會得到一個"Cannot implicitly convert type 'int' to 'string'"的錯誤。   static void Main(string[] args) {     var str = "hello world";//string str = "hello world";     str = 9;     Console.Read(); } 隱式類型的限制 使用隱式類型的時候,會有一些限制,不是所有變量都能使用隱式類型:   被聲明的變量是一個局部變量,不能是靜態字段和實例字段 變量在聲明時必須被初始化 編譯器需要根據變量的值來推斷變量的類型,否則就會出現編譯時錯誤 初始化表達式不能為一個方法組,也不能為一個匿名函數(不進行強制類型轉化) var enter = delegate { Console.WriteLine(); };//編譯錯誤 var enter = (Action)delegate { Console.WriteLine(); };//正常,因為編譯器可以進行類型推斷 初始化表達式不是null 因為null可以隱式轉化為任何引用類型或可空類型,所以編譯器不能進行類型推斷 語句中只能聲明一個變量 "var a = 2, b = 3;"會得到編譯錯誤 隱式類型的優缺點 有些時候使用隱式類型可以減少代碼長度,通過不影響代碼可讀性,反而使我們把注意力放在了更有用的代碼上;但是,有時候隱式類型會是代碼可讀性變差。所以要自己衡量什麼時候使用隱式類型的變量。下面看一個簡單的例子     static void Main(string[] args) {     //簡化了代碼,沒有犧牲可讀性     var wordCount = new Dictionary<string, int>();     foreach (var dict in wordCount)     {         Console.WriteLine("number of {0} is {1}", dict.Key, dict.Value);     }       //可讀性變差,不容易從代碼中直接看出變量類型     var numA = 2147483647;     var numB = 2147483648;     var numC = 4294967295;       Console.WriteLine(numA.GetType());     Console.WriteLine(numB.GetType());     Console.WriteLine(numC.GetType());          Console.Read(); }   隱式類型的局部變量對象和集合初始化程序 在C# 3.0中,我們有了新的對象和集合初始化的方法。   對象初始化程序(object initializers) 當我們有了對象初始化程序的時候,對象初始化的代碼就變得更加直觀、簡單。看一個例子:     public class Book {     public int Id { get; set; }     public string Title { get; set; }       //如果沒有默認的構造函數,使用對象初始化時就會報錯     public Book()     {     }       public Book(string title)     {         this.Title = title;     } }   class Program {     static void Main(string[] args)     {         //C# 3.0之前初始化對象的方法         Book b1 = new Book();         b1.Id = 1;         b1.Title = "C# step by step";           //使用對象初始化程序         Book b2 = new Book(){Id = 2, Title = "C# in depth"};         Book b3 = new Book { Id = 3, Title = "C# in depth" };         Book b4 = new Book("C# in depth") { Id = 1};       } }   當我們查看IL代碼會發現,b1、b2和b3的IL代碼完全一樣。   集合初始化列表(collection initializers) 在C# 3.0中還提出來集合初始化列表,我們可以輕松的實現集合的初始化工作。   接著上面的例子,我們可以創建圖書列表:     //C# 3.0之前初始化集合的方法 List<Book> bookList1 = new List<Book>(); bookList1.Add(b1); bookList1.Add(b2); bookList1.Add(b3); bookList1.Add(b4);   //使用集合初始化程序 List<Book> bookList2 = new List<Book> { b1, b2, b3, b4 };   List<Book> bookList3 = new List<Book> {     new Book{Id = 5, Title = "Java in depth"},     new Book{Id = 6, Title = "Python in depth"}, };   可以看到,當使用了集合初始化列表之後,代碼變得更加簡潔了。   通過查看IL代碼我們可以發現,使用集合初始化列表的時候,其實編譯器幫我們調用了List的Add方法進行了元素的添加。   隱式類型的數組 在C# 1.0和C# 2.0中,當我們使用數組的時候,必須要指定涉及的具體數組類型。   在C# 3.0中,可以使用"new[]"來聲明並初始化一個隱式類型的數組。   看一個簡單的例子:     string[] names = { "Wilber", "Will", "July" }; PrintName(names); PrintName(new string[] { "Wilber", "Will" });   //C# 3.0中使用匿名類型數組,編譯器負責推斷數組類型 PrintName(new[] { "Wilber", "Will" }); var nameArray = new[] { "Wilber", "Will", "July" }; PrintName(nameArray);   //無法進行類型推斷,編譯器報錯 //var array = new[] { 1, "hello world" }; …… private static void PrintName(string []names) {     foreach (var name in names)     {         Console.WriteLine(name);     } }   匿名類型 在C# 3.0之前,當我們創建對象的時候,我們需要一個類型。在C# 3.0中出現了匿名類型的概念(類似於匿名方法,編譯器幫我們完成了很多工作),我們可以直接通過new關鍵字為對象定義了屬性,並且為這些屬性賦值。   看一個例子:     static void Main(string[] args) {     //創建匿名對象     //通過匿名對象初始化程序為屬性賦值     var student = new { Name = "Wilber", Age = 28, Gender = "Male" };     Console.WriteLine("{0} is {1} years old", student.Name, student.Age);       //使用隱式類型的數組初始化列表     var school = new[] {         //使用同一個匿名類型創建實例         new {Name = "Wilber", Gender = "Male", Age = 28 },         new {Name = "Will", Gender = "Male", Age = 27 },         new {Name = "Lily", Gender = "Female", Age = 26 },     };       int totalAge = 0;     foreach (var stu in school)     {         totalAge += stu.Age;     }       Console.WriteLine(totalAge);     Console.Read(); }

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved