国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

C#泛型

2019-11-17 03:02:16
字體:
來源:轉載
供稿:網友

C#泛型

一、泛型概述

二、泛型的優點

三、泛型類型參數

四、類型參數的約束

五、泛型類

六、泛型接口

七、泛型方法

八、泛型委托1

九、泛型代碼中的default 關鍵字

十、C++ 模板和C# 泛型的區別

十一 、運行時中的泛型

十二 、基礎類庫中的泛型

前言

泛型(generic)是C#語言2.0和通用語言運行時(CLR)的一個新特性。泛型為.NET框架引入了類型參數(type parameters)的概念。類型參數使得設計類和方法時,不必確定一個或多個具體參數,其的具體參數可延遲到客戶代碼中聲明、實現。這意味著使用泛型的類型參數T,寫一個類MyList<T>,客戶代碼可以這樣調用:MyList<int>, MyList<string>或 MyList<MyClass>。這避免了運行時類型轉換或裝箱操作的代價和風險。

一、泛型概述

泛型類和泛型方法兼復用性、類型安全和高效率于一身,是與之對應的非泛型的類和方法所不及。泛型廣泛用于容器(collections)和對容器操作的方法中。.NET框架2.0的類庫提供一個新的命名空間System.Collections.Generic,其中包含了一些新的基于泛型的容器類。要查找新的泛型容器類(collection classes)的示例代碼,請參見基礎類庫中的泛型。當然,你也可以創建自己的泛型類和方法,以提供你自己的泛化的方案和設計模式,這是類型安全且高效的。下面的示例代碼以一個簡單的泛型鏈表類作為示范。(多數情況下,推薦使用由.NET框架類庫提供的List<T>類,而不是創建自己的表。)類型參數T在多處使用,具體類型通常在這些地方來指明表中元素的類型。類型參數T有以下幾種用法:

  • 在AddHead方法中,作為方法參數的類型。
  • 在公共方法GetNext中,以及嵌套類Node的 Data屬性中作為返回值的類型。
  • 在嵌套類中,作為私有成員data的類型。

注意一點,T對嵌套的類Node也是有效的。當用一個具體類來實現MyList<T>時——如MyList<int>——每個出現過的T都要用int代替。

 1 using System; 2 using System.Collections.Generic; 3  4 public class MyList<T> //type parameter T in angle brackets 5     { 6         PRivate Node head; 7 // The nested type is also generic on T. 8         private class Node         9         {10             private Node next;11 //T as private member data type:12             private T data;          13 //T used in non-generic constructor:14             public Node(T t)         15             {16                next = null;17                 data = t;18             }19             public Node Next20             {21                 get { return next; }22                 set { next = value; }23             }24 25 //T as return type of property:26             public T Data            27             {28                 get { return data; }29                 set { data = value; }30             }31         }32         public MyList()33         {34             head = null;35         }36 //T as method parameter type:37         public void AddHead(T t)     38         {39             Node n = new Node(t);40             n.Next = head;41             head = n;42         }43         public IEnumerator<T> GetEnumerator()44         {45            Node current = head;46           while (current != null)47             {48                 yield return current.Data;49                 current = current.Next;50             }51         }52     }
View Code

下面的示例代碼演示了客戶代碼如何使用泛型類MyList<T>,來創建一個整數表。通過簡單地改變參數的類型,很容易改寫下面的代碼,以創建字符串或其他自定義類型的表。

class Program

{

static void Main(string[] args)

{

//int is the type argument.

MyList<int> list = new MyList<int>();

for (int x = 0; x < 10; x++)

list.AddHead(x);

foreach (int i in list)

{

Console.WriteLine(i);

}

Console.WriteLine("Done");

}

}

二、泛型的優點

針對早期版本的通用語言運行時和C#語言的局限,泛型提供了一個解決方案。以前類型的泛化(generalization)是靠類型與全局基類System.Object的相互轉換來實現。.NET框架基礎類庫的ArrayList容器類,就是這種局限的一個例子。ArrayList是一個很方便的容器類,使用中無需更改就可以存儲任何引用類型或值類型。

//The .NET Framework 1.1 way of creating a list

ArrayList list1 = new ArrayList();

list1.Add(3);

list1.Add(105);

//...

ArrayList list2 = new ArrayList();

list2.Add("It is raining in Redmond.");

list2.Add("It is snowing in the mountains.");

//...

但是這種便利是有代價的,這需要把任何一個加入ArrayList的引用類型或值類型都隱式地向上轉換成System.Object。如果這些元素是值類型,那么當加入到列表中時,它們必須被裝箱;當重新取回它們時,要拆箱。類型轉換和裝箱、拆箱的操作都降低了性能;在必須迭代(iterate)大容器的情況下,裝箱和拆箱的影響可能十分顯著。另一個局限是缺乏編譯時的類型檢查,當一個ArrayList把任何類型都轉換為Object,就無法在編譯時預防客戶代碼類似這樣的操作:

ArrayList list = new ArrayList();

//Okay.

list.Add(3);

//Okay, but did you really want to do this?

list.Add(."It is raining in Redmond.");

int t = 0;

//This causes an InvalidCastException to be returned.

foreach(int x in list)

{

t += x;

}

雖然這樣完全合法,并且有時是有意這樣創建一個包含不同類型元素的容器,但是把string和int變量放在一個ArrayList中,幾乎是在制造錯誤,而這個錯誤直到運行的時候才會被發現。在1.0版和1.1版的C#語言中,你只有通過編寫自己的特定類型容器,才能避免.NET框架類庫的容器類中泛化代碼(generalized code)的危險。當然,因為這樣的類無法被其他的數據類型復用,也就失去泛型的優點,你必須為每個需要存儲的類型重寫該類。ArrayList和其他相似的類真正需要的是一種途徑,能讓客戶代碼在實例化之前指定所需的特定數據類型。這樣就不需要向上類型轉換為Object,而且編譯器可以同時進行類型檢查。換句話說,ArrayList需要一個類型參數。這正是泛型所提供的。在System.Collections.Generic命名空間中的泛型List<T>容器里,同樣是把元素加入容器的操作,類似這樣:

The .NET Framework 2.0 way of creating a list

List<int> list1 = new List<int>();

//No boxing, no casting:

list1.Add(3);

//Compile-time error:

list1.Add("It is raining in Redmond.");

與ArrayList相比,在客戶代碼中唯一增加的List<T>語法是聲明和實例化中的類型參數。代碼略微復雜的回報是,你創建的表不僅比ArrayList更安全,而且明顯地更加快速,尤其當表中的元素是值類型的時候。

三、泛型類型參數

在泛型類型或泛型方法的定義中,類型參數是一個占位符(placeholder),通常為一個大寫字母,如T。在客戶代碼聲明、實例化該類型的變量時,把T替換為客戶代碼所指定的數據類型。泛型類,如泛型概述中給出的MyList<T>類,不能用作as-is,原因在于它不是一個真正的類型,而更像是一個類型的藍圖。要使用MyList<T>,客戶代碼必須在尖括號內指定一個類型參數,來聲明并實例化一個已構造類型(constructed type)。這個特定類的類型參數可以是編譯器識別的任何類型。可以創建任意數量的已構造類型實例,每個使用不同的類型參數,如下:

MyList<MyClass> list1 = new MyList<MyClass>();

MyList<float> list2 = new MyList<float>();

MyList<SomeStruct> list3 = new MyList<SomeStruct>();

在這些MyList<T>的實例中,類中出現的每個T都將在運行的時候被類型參數所取代。依靠這樣的替換,我們僅用定義類的代碼,就創建了三個獨立的類型安全且高效的對象。有關CLR執行替換的詳細信息,請參見運行時中的泛型。

四、類型參數的約束

若要檢查表中的一個元素,以確定它是否合法或是否可以與其他元素相比較,那么編譯器必須保證:客戶代碼中可能出現的所有類型參數,都要支持所需調用的操作或方法。這種保證是通過在泛型類的定義中,應用一個或多個約束而得到的。一個約束類型是一種基類約束,它通知編譯器,只有這個類型的對象或從這個類型派生的對象,可被用作類型參數。一旦編譯器得到這樣的保證,它就允許在泛型類中調用這個類型的方法。上下文關鍵字where用以實現約束。下面的示例代碼說明了應用基類約束,為MyList<T>類增加功能。

public class Employee

{

public class Employee

{

private string name;

private int id;

public Employee(string s, int i)

{

name = s;

id = i;

}

public string Name

{

get { return name; }

set { name = value; }

}

public int ID

{

get { return id; }

set { id = value; }

}

}

}

class MyList<T> where T: Employee

{

//Rest of class as before.

public T FindFirstOccurrence(string s)

{

T t = null;

Reset();

while (HasItems())

{

if (current != null)

{

//The constraint enables this:

if (current.Data.Name == s)

{

t = current.Data;

break;

}

else

{

current = current.Next;

}

} //end if

} // end while

return t;

}

}

約束使得泛型類能夠使用Employee.Name屬性,因為所有為類型T的元素,都是一個Employee對象或是一個繼承自Employee的對象。同一個類型參數可應用多個約束。約束自身也可以是泛型類,如下:

class MyList<T> where T: Employee, IEmployee, IComparable<T>, new()

{&hellip;}

下表列出了五類約束:

約束

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 宜章县| 庄河市| 韶关市| 昌邑市| 西充县| 都江堰市| 泰州市| 苍山县| 南丹县| 洛阳市| 曲沃县| 金阳县| 北京市| 广汉市| 阿坝| 吐鲁番市| 古田县| 尖扎县| 吉木乃县| 汉中市| 府谷县| 遵义县| 九江县| 迁西县| 黑水县| 班戈县| 常州市| 巴彦淖尔市| 沁源县| 金沙县| 共和县| 孟村| 宜兴市| 昭平县| 华容县| 资阳市| 罗源县| 万州区| 大庆市| 科技| 汨罗市|

  • <small id="9nxr3"><tbody id="9nxr3"></tbody></small>
      <track id="9nxr3"></track>
    1. <sub id="9nxr3"><tr id="9nxr3"><th id="9nxr3"></th></tr></sub>
      <small id="9nxr3"><tbody id="9nxr3"></tbody></small>