天天看點

C#泛型方法解析

C#2.0引入了泛型這個特性,由于泛型的引入,在一定程度上極大的增強了C#的生命力,可以完成C#1.0時需要編寫複雜代碼才可以完成的一些功能。但是作為開發者,對于泛型可謂是又愛又恨,愛的是其強大的功能,以及該特性帶來的效率的提升,恨的是泛型在複雜的時候,會呈現相當複雜的文法結構。這種複雜不僅是對于初學者,對于一些有開發經驗的.NET開發者,也是一個不那麼容易掌握的特性。

   接下來我們來了解一下C#2.0加入的特性:泛型。

    在實際項目開發中,任何API隻要将object作為參數類型和傳回類型使用,就可能在某個時候涉及強類型轉換。提到強類型轉換,估計很多開發者第一反應就是“效率”這個次,對于強類型的利弊主要看使用者使用的環境,天底下沒有絕對的壞事,也沒有絕對的好事,有關強類型的問題不是本次的重點,不做重點介紹。

    泛型是CLR和C#提供的一種特殊機制,支援另一種形式的代碼重用,即“算法重用”。泛型實作了類型和方法的參數化,泛型類型和方法也可以讓參數告訴使用者使用什麼類型。

    泛型所帶來的好處:更好的編譯時檢查,更多在代碼中能直接表現的資訊,更多的IDE支援,更好的性能。可能有人會疑問,為什麼泛型會帶來這麼多好處,使用一個不能區分不同類型的正常API,相當于在一個動态環境中通路那個API。

    CLR允許建立泛型引用和泛型值類型,但是不允許建立泛型枚舉,并且CLR允許建立泛型接口和泛型委托,CLR允許在引用類型、值類型或接口中定義泛型方法。定義泛型類型或方法時,為類型指定了任何變量(如:T)都稱為類型參數。(T是一個變量名,在源代碼中能夠使用一個資料類型的任何位置,都可以使用T)在C#中泛型參數變量要麼成為T,要麼至少一大寫T開頭。

     泛型類型仍然是類型,是以可以從任何類型派生。使用一個泛型類型并指定類型實參時,實際是在CLR中定義一個新類型對象,新類型對象是從泛型派生自的那個類型派生的。使用泛型類型參數的一個方法在基尼險那個JIT編譯時,CLR擷取IL,用指定的類型實參進行替換,然後建立恰當的本地代碼。

    如果沒有為泛型類型參數提供類型實參,那就麼就是未綁定泛型類型。如果指定了類型實參,該類型就是已構造類型。已構造類型可以是開發或封閉的,開發類型還包含一個類ixngcanshu,而封閉類型則不是開發的,類型的每個部分都是明确的。所有代碼實際都是在一個封閉的已構造類型的上下文中執行。

   泛型類在.NET的應用主要在集合類中,大多數集合類在System.Collections.Generic和System.Collections.ObjectModel類中。下面簡單的介紹一種泛型集合類:

     (1).SynchronizedCollection:提供一個線程安全集合,其中包含泛型參數所指定類型的對象作為元素.

   (2).KeyedByTypeCollection:提供一個集合,該集合的項是用作鍵的類型。

     泛型的主要作用就是定義泛型的引用類型和指類型。一個引用類型或值類型可通過指定類型實參的方式實作泛型接口,也可以保持類型實參的未指定狀态實作一個泛型接口。

     具體看一下泛型接口IEnumerable:公開枚舉數,該枚舉數支援在非泛型集合上進行簡單疊代。

    CLR支援泛型委托,目的是保證任何類型的對象都能以一種類型安全的方式傳給一個回調方法。泛型委托允許一個孩子類型執行個體在傳給一個回調方法時不執行任何裝箱處理。委托時機隻提供了4個方法:一個構造器,一個Invlke方法,一個BeginInvoke方法和一個EndInvoke方法。如果定義的一個委托類型指定了類型參數,編譯器會定義委托類的方法,用指定的類型參數替換方法的參數類型和值類型。

   以上是對泛型類、泛型接口和泛型委托的簡單了解,本文的目的主要是講解泛型方法,下面我們具體了解一些泛型泛型的知識。

    定義泛型類、結構或接口時,類型中定義的任何方法都可引用類型指定的一個類型參數。類型參數可以作為方法的參數,作為方法的傳回值,或者作為方法内部定義的一個局部變量來使用。CLR允許一個方法指定它獨有的類型參數,這些類型參數可用于參數、傳回值、或者局部變量。

   C#編譯器支援在調用一個泛型方法時進行類型推斷。執行類型推斷時,C#使用變量的資料類型,而不是由變量引用的對象的實際類型。一個類型可以定義多個方法,讓其中一個方法接受具體的資料類型,讓另一個方法接受泛型類型參數。

    泛型方法示例:

    對以上的示例代碼分析,需要掌握:為每個類型參數使用一個不同的類型,在整體應用這些類型參數。

  (1).首先替換包含方法(List<T>的T部分)的那個類型的類型參數,如将T替換為string:

  (2).處理完T後,再需要處理的就是TOutput,可以看出它是一個方法類型參數,這裡采用guid替換TOutput。

  對TOutput賦予類型實參後,可以移除生命中的類型參數<TOutput>,将方法堪稱非泛型方法,如上。以上的示例可以處理一個字元串清單,用一個轉換器來生成一個Guid清單。

  将原始清單中的每個元素都轉換成目标類型,将轉換後的元素添加到一個清單中,最後傳回這個清單。以上的處理方式,主要将其泛型方法的參數進行逐一的細化,無論在什麼學科,都需要将複雜的問題進行簡單化,将抽象的問題具體化,這也是一種常用的處理方式。

    限制的作用是限制能指定成泛型實參的類型數量。通過限制類型的數量,我們可以對那些類型執行更多的操作。限制可以應用于一個泛型類型的類型參數,也可以應用于一個泛型方法的類型參數。CLR不允許基于類型參數名稱或限制進行重載,隻能基于元數對類型或方法進行重載。不允許為重寫方法的類型參數指定任何限制,但是類型實參的名稱是可以改變的。

    泛型限制的操作,限制要放到泛型方法或泛型類型聲明的末尾,并由上下文關鍵where引入。

      引用類型限制:用于確定使用的類型實參是引用類型。(表示為:T:class,且必須為類型參數指定的第一個限制。)

      值類型限制:用于確定使用的類型參數是指類型。(表示為:T:struct,可空類型不包含在内)

      構造函授類型限制:指定所有類型參數的最後一個限制,它檢查類型實參是否有一個可用于建立執行個體的無參構造函數。(表示為:T:new())适用于所有值類型,所有沒有顯示聲明構造函數的非靜态、非抽象類,所有顯示聲明了一個公共無參構造函數的非抽象類。

     轉換類型限制:允許你指定另一個類型,類型實參必須可以通過一緻性、引用或裝箱轉換隐式地轉換為該類型。還可以規定類型實參必須可以轉換為另一個類型實參。(例:class Sample<T> where T:Stream)

     組合限制:所個限制組合在一起的限制,但是組合限制也有限制條件。因為沒有任何類型即是引用類型,又是值類型。由于每一個值都有一個無參構造函數,是以假如已經有一個值類型限制,就不允許再指定一個構造函數限制。如果存在多個類型限制,并且其中一個為類,那麼它應該出現在接口的前面,而且我們不能多次指定同一個接口。不同的類型參數可以用不同的限制,分别由一個where引入。

   備注:類型推斷隻适用于泛型方法,不适用于泛型類型。

  以上是對泛型方法的相關概念和限制做了簡單的解析,接下來看一下.NET中一些發行方法的具體實作:

   以上講解的有關泛型方法的内容,這裡提供一個有關泛型方法操作XML的代碼:

   以上的代碼就不做贅述,需要次代碼的可以使用。

本文轉自  zddnd  51CTO部落格,原文連結:http://blog.51cto.com/13013666/1939715

繼續閱讀