歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 理解隱式類型、對象初始化程序和匿名類型

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

日期:2017/3/1 9:32:02   编辑:Linux編程

在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代碼完全一樣。

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2015-02/114146p2.htm

Copyright © Linux教程網 All Rights Reserved