分類: 泛型
c#應用
2009-02-25 10:04
550人閱讀收藏
舉報 前言
.net 2.0中泛型的出現是乙個令人激動的特徵。但是,什麼是泛型?你需要它們嗎?你會在自己的應用軟體中使用它們?在本文中,我們將回答這些問題並細緻地分析泛型的使用,能力及其侷限性。
型別安全
.net中的許多語言如c#,c++和vb.net(選項strict為on)都是強型別語言。作為乙個程式設計師,當你使用這些語言時,總會期望編譯器進行型別安全的檢查。例如,如果你把對乙個book型別的引用轉換成乙個vehicle型的引用,編譯器將告訴你這樣的cast是無效的。
然而,當談到.net 1.0和1.1中的集合時,它們是無助於型別安全的。請考慮乙個arraylist的例子,它擁有乙個物件集合--這允許你把任何型別的物件放於該arraylist中。讓我們看一下例1中的**。
例1.缺乏型別安全的arraylist
本例中,我們建立了乙個arraylist的例項,並把3和4新增給它。然後我迴圈遍歷該arraylist,從中取出整型值然後把它們相加。這個程式將產生結果"total is 7"。現在,如果我注釋掉下面這句:
list.add(5.0);
程式將產生如下的執行時刻異常:
**出錯了呢?記住arraylist擁有乙個集合的物件。當你把3加到arraylist上時,你已把值3裝箱了。當你迴圈該列表時,你是把元素拆箱成int型。然而,當你新增值5.0時,你在裝箱乙個double型值。在第17行,那個double值被拆箱成乙個int型。這就是失敗的原因。
注意:上面的例項,如果是用vb.net書寫的話,是不會失敗的。原因在於,vb.net不使用裝箱機制,它啟用乙個把該double轉換成整型的方法。但是,如果arraylist中的值是不能轉換成整型的,vb.net**還會失敗。
作為乙個習慣於使用語言提供的型別安全的程式設計師,你希望這樣的問題在編譯期間浮出水面,而不是在執行時刻。這正是泛型產生的原因。
3. 什麼是泛型?
泛型允許你在編譯時間實現型別安全。它們允許你建立乙個資料結構而不限於一特定的資料型別。然而,當使用該資料結構時,編譯器保證它使用的型別與型別安全是相一致的。泛型提供了型別安全,但是沒有造成任何效能損失和**臃腫。在這方面,它們很類似於c++中的模板,不過它們在實現上是很不同的。
4. 使用泛型集合
.net 2.0的system.collections.generics 命名空間包含了泛型集合定義。各種不同的集合/容器類都被"引數化"了。為使用它們,只需簡單地指定引數化的型別即可。請看例2:
例2.型別安全的泛型列表
list<int> alist = new list<int>();
alist.add(3);
alist.add(4);
// alist.add(5.0);
int total = 0;
foreach(int val in alist)
console.writeline("total is ", total);
在例2中,我編寫了乙個泛型的列表的例子,在尖括號內指定引數型別為int。該**的執行將產生結果"total is 7"。現在,如果我去掉語句doublelist.add(5.0)的注釋,我將得到乙個編譯錯誤。編譯器指出它不能傳送值5.0到方法add(),因為該方法僅接受int型。不同於例1,這裡的**實現了型別安全。
5. clr對於泛型的支援
泛型不僅是乙個語言級上的特徵。.net clr能識別出泛型。在這種意義上說,泛型的使用是.net中最為優秀的特徵之一。對每個用於泛型化的型別的引數,類也同樣沒有脫離開微軟中間語言(msil)。換句話說,你的配件集僅包含你的引數化的資料結構或類的乙個定義,而不管使用多少種不同的型別來表達該引數化的型別。例如,如果你定義乙個泛型型別mylist<t>,僅僅該型別的乙個定義出現在msil中。當程式執行時,不同的類被動態地建立,每個類對應該引數化型別的一種型別。如果你使用mylist<int>和mylist<double>,有兩種類即被建立。當你的程式執行時,讓我們進一步在例3中分析這一點。
例3.建立乙個泛型類
#region using directives
using system;
using system.collections.generic;
using system.text;
#endregion
namespace clrsupportexample
public int count}}
}#region using directives
using system;
using system.collections.generic;
using system.text;
#endregion
namespace clrsupportexample
class program}}
該例中,我建立了乙個稱為mylist泛型類。為把它引數化,我簡單地插入了乙個尖括號。在<>內的t代表了實際的當使用該類時要指定的型別。在mylist類中,定義了乙個靜態欄位objcount。我在構造器中增加它的值。因此我能發現使用我的類的使用者共建立了多少個那種型別的物件。屬性count返回與被呼叫的例項同型別的例項的數目。
在main()方法,我建立了mylist<int>的兩個例項,乙個mylist<double>的例項,還有兩個mylist<sampleclass>的例項--其中sampleclass是我已定義了的類。問題是:count(上面的程式的輸出)的值該是多少?在你繼閱讀之前,試一試回答這個問題。
解決了上面的問題?你得到下列的答案了嗎?22
112
前面兩個2對應mylist<int>,第乙個1對應mylist<double>,第二個1對應mylist<sampleclass>--在此,僅建立乙個這種型別的例項。最後乙個2對應mylist<sampleclass>,因為**中又建立了這種型別的另外乙個例項。上面的例子說明mylist<int>是乙個與mylist<double>不同的類,而mylist<double>又是乙個與mylist<sampleclass>不同的類。因此,在這個例中,我們有四個類:mylist: mylist<t>,mylist<int>,mylist<double>和mylist<x>。注意,雖然有4個mylist類,但僅有乙個被儲存在msil。怎麼能證明這一點?請看圖1顯示出的使用工具ildasm.exe生成的msil**。
圖 1.例3的msil
6. 泛型方法
除了有泛型類,你也可以有泛型方法。泛型方法可以是任何類的一部分。讓我們看一下例4:
例4.乙個泛型方法
public class program
}static void main(string args)}
copy()方法就是乙個泛型方法,它與引數化的型別t一起工作。當在main()中啟用copy()時,編譯器根據提供給copy()方法的引數確定出要使用的具體型別。
泛型 什麼是泛型
泛型 即通過引數化型別來實現在同乙份 上操作多種資料型別。泛型程式設計是一種程式設計正規化,它利用 引數化型別 將型別抽象化,從而實現更為靈活的復用。c 泛型的作用概述 c 泛型賦予了 更強的型別安全,更好的復用,更高的效率,更清晰的約束。在乙個方法中,乙個變數的值是可以作為引數,但其實這個變數的型...
泛型 為什麼是泛型?
需求 先需編寫乙個程式,用棧 stack 進行進棧和出棧操作,並對棧中的元素進行運算。方案一 假設元素為int型別,則可使用 code class stack public void push int x public int pop 客戶 code class test 然而,現在需求發生變化。客...
關於泛型,什麼是泛型,如何理解泛型
泛型是jdk5中引入的特性,它提供了編譯時型別安全檢測機制,該機制允許在編譯時檢測到非法的型別,就不至於在執行時出現轉換異常,它的本質是引數化型別 即以任何型別 t 作為引數,在使用時可以傳入型別t的具體值 t 也就是將型別由原來的具體型別用引數t表示 即型別引數化 然後在使用 呼叫時傳入具體的型別...