/*在此申明有些是来自msdn*/
泛型介绍
泛型是
2.0
版
C#
语言和公共语言运行库
(CLR)
中的一个新功能。泛型将类型参数的概念引入
.NET Framework
,类型参数使得设计如下类和方法成为可能:这些类和方法将一个或多个类型的指定推迟到客户端代码声明并实例化该类或方法的时候。例如,通过使用泛型类型参数
T
,您可以编写其他客户端代码能够使用的单个类,而不致引入运行时强制转换或装箱操作的成本或风险,所谓泛型:即通过参数化类型来实现在同一份代码上操作多种数据类型。泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。
一.泛型概述
:
1.
使用泛型类型可以最大限度地重用代码、保护类型的安全以及提高性能。
2.
泛型最常见的用途是创建集合类。
3..NET Framework
类库在
System.Collections.Generic
命名空间中包含几个新的泛型集合类。应尽可能地使用这些类来代替普通的类,如
System.Collections
命名空间中的
ArrayList
。
4.
您可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。
5.
可以对泛型类进行约束以访问特定数据类型的方法。
关于泛型数据类型中使用的类型的信息可在运行时通过反射获取。
如下例子所示:
注:以下所有的例子的名字窨
StudyC.Class
,请注意。
1.
以下是显示一个泛型堆栈类
using
System;
//using System.Collections.Generic;
using
System.Text;
namespace
StudyC.Class
{
///<summary>
///
以下是显示一个泛型堆栈类
///</summary>
///<typeparam name="T">
参数类型
</typeparam>
class Stack<T>
{
private T[] store;
private int iPos;
public Stack()
{
store = new T[10];
iPos = 0;
}
public Stack(int iLen)
{
store = new T[iLen];
iPos = 0;
}
public void Push(T x)
{
store[iPos++] = x;
}
public T Pop()
{
return store[--iPos];
}
}
}
下面的代码示例演示客户端代码如何使用泛型 Stack <T> 类来堆栈表。只需更改类型参数,即可方便地修改下面的代码示例,创建字符串或任何其他自定义类型的堆栈表:
Stack
<int> x = new Stack<int>();
x.Push(17);
x.Push(18);
x.Push(34);
MessageBox
.Show(x.Pop().ToString());
MessageBox
.Show(x.Pop().ToString());
显示顺序34,18
Stack
<string> s = new Stack<string>();
s.Push("ddd");
s.Push("rrr");
s.Push("CCC");
MessageBox
.Show(s.Pop().ToString());
MessageBox
.Show(s.Pop().ToString());
显示顺序CCC,rrr
2.
创建列表
,也链表
class
GenericList<T>
{
//
嵌套类型也是T 上的泛型
private class Node
{
//
类型T来构造此类
public Node(T t)
{
next = null;
data = t;
}
private Node next;
public Node Next
{
get { return next; }
set { next = value; }
}
// T
作为私有成员数据类型。
private T data;
// T
作为属性成员数据类型。
public T Data
{
get { return data; }
set { data = value; }
}
}
private Node head;
//
构造函数
public GenericList()
{
head = null;
}
// T
作为方法参数类型。
public void AddHead(T t)
{
Node n = new Node(t);
n.Next = head;
head = n;
}
///<summary>
///
注:支持在泛型在集合上迭代,也就是用foreach(T is T)结构迭代,这个循环找数据
///</summary>
///<returns></returns>
public IEnumerator<T> GetEnumerator()
{
Node current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
}
下面的代码示例演示客户端代码如何使用泛型
GenericList<T>
类来创建整数列表。只需更改类型参数,即可方便地修改下面的代码示例,创建字符串或任何其他自定义类型的列表:
StudyC.Class.GenericList<int> list = new StudyC.Class.GenericList<int>();
for
(int m = 0; m < 10; m++)
{
list.AddHead(m);
}
foreach
(int i in list)
{
MessageBox.Show(i + " ");
}
二.
泛型类型参数
在泛型类型或方法定义中,类型参数是客户端在实例化泛型类型的变量时指定的特定类型的占位符。泛型类(如
泛型介绍(C# 编程指南)
中列出的
GenericList<T>
)不可以像这样使用,因为它实际上并不是一个类型,而更像是一个类型的蓝图。若要使用
GenericList<T>
,客户端代码必须通过指定尖括号中的类型参数来声明和实例化构造类型。此特定类的类型参数可以是编译器识别的任何类型。可以创建任意数目的构造类型实例,每个实例使用不同的类型参数,如以上所示:
StudyC.Class.GenericList<int> list = new StudyC.Class.GenericList<int>();
在每个
GenericList<T>
实例中,类中出现的每个
T
都会在运行时替换为相应的类型参数。通过这种替换方式,我们使用一个类定义创建了三个独立的类型安全的有效对象。
三.
类型参数的约束
在定义泛型类时,可以对客户端代码能够在实例化类时用于类型参数的类型种类施加限制。如果客户端代码尝试使用某个约束所不允许的类型来实例化类,则会产生编译时错误。这些限制称为约束。约束是使用 where 上下文关键字指定的。下表列出了五种类型的约束:
T
:结构
类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。有关更多信息,请参见使用可空类型
T
:类
类型参数必须是引用类型,包括任何类、接口、委托或数组类型。
T
:new()
类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。
T
:<基类名>
类型参数必须是指定的基类或派生自指定的基类。
T
:<接口名称>
类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。
T
:U
为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。
如果要检查泛型列表中的某个项以确定它是否有效,或者将它与其他某个项进行比较,则编译器必须在一定程度上保证它需要调用的运算符或方法将受到客户端代码可能指定的任何类型参数的支持。这种保证是通过对泛型类定义应用一个或多个约束获得的。例如,基类约束告诉编译器:仅此类型的对象或从此类型派生的对象才可用作类型参数。一旦编译器有了这个保证,它就能够允许在泛型类中调用该类型的方法。约束是使用上下文关键字 where 应用的.
举个例子说明
///
定义一个类,为后面的泛型而约束
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; }
}
}
public
class GenericList<T> where T : Employee
{
private class Node
{
private Node next;
private T data;
public Node(T t)
{
next = null;
data = t;
}
public Node Next
{
get { return next; }
set { next = value; }
}
public T Data
{
get { return data; }
set { data = value; }
}
}
private Node head;
public GenericList() //constructor
{
head = null;
}
///<summary>
///
堆栈形式进入链表,将其链接起来(其实算法是先进后出,插入的每个值都做为链表头)
///</summary>
///<param name="t"></param>
public void AddHead(T t)
{
Node n = new Node(t);
n.Next = head;
head = n;
}
///<summary>
///
其算法是插入的每个值都放在表头指针的后面
///</summary>
///<param name="t"></param>
public void AddFirstNext(T t)
{
Node n = new Node(t);
if (head == null)
{
head = n;
}
else
{
n.Next = head.Next;
head.Next = n;
}
}
///<summary>
///
注:支持在泛型在集合上迭代,也就是用foreach(T is T)结构迭代,这个循环找数据
///
实现GetEnumerator 以返回IEnumerator<T>,从而启用列表的
/// foreach
迭代。请注意,在C# 2.0 中,不需要实现Current 和MoveNext。
///
编译器将创建实现IEnumerator<T> 的类。
///</summary>
///<returns></returns>
public IEnumerator<T> GetEnumerator()
{
Node current = head;
while (current != null)
{
yield return current.Data;
current = current.Next;
}
}
///<summary>
///
查找字符串s是否在泛型类似T约束Employee里的Name,要是存在就返回其当然Employee的对象,也就是T的约束Employee对象
///</summary>
///<param name="s">
字符串值
</param>
///<returns>
返回T的约束Employee对象
</returns>
public T FindFirstOccurrence(string s)
{
Node current = head;
T t = null;
while (current != null)
{
//The constraint enables access to the Name property
if (current.Data.Name == s)
{
t = current.Data;
break;
}
else
{
if (current.Next == null)
{
current = null;
t = null;
}
else
{
current = current.Next;
}
}
}
return t;
}
}
在客户端调用
StudyC.Class.Employee em = new StudyC.Class.Employee("A", 1);
StudyC.Class.Employee em1 = new StudyC.Class.Employee("B", 2);
StudyC.Class.Employee em2 = new StudyC.Class.Employee("c", 3);
StudyC.Class.Employee em3 = new StudyC.Class.Employee("d", 3);
StudyC.Class.GenericList<StudyC.Class.Employee> list = new StudyC.Class.GenericList<StudyC.Class.Employee>();
StudyC.Class.GenericList<StudyC.Class.Employee> list2 = new StudyC.Class.GenericList<StudyC.Class.Employee>();
list.AddHead(em);
list.AddHead(em1);
list.AddHead(em2);
list.AddHead(em3);
list2.AddFirstNext(em);
list2.AddFirstNext(em1);
list2.AddFirstNext(em2);
list2.AddFirstNext(em3);
em = list.FindFirstOccurrence("hide");
if
(em != null)
{ MessageBox.Show(em.Name.ToString() + "ddrrr"); }
try
{
listBox1.Items.Add("list's data");
foreach
(StudyC.Class.Employee ep in list)
{
listBox1.Items.Add(ep.Name + " ;" + ep.ID);
}
listBox1.Items.Add("list2's data");
foreach
(StudyC.Class.Employee ep2 in list2)
{
listBox1.Items.Add(ep2.Name + " ;" + ep2.ID);
}
}
catch
(Exception ex)
{
MessageBox.Show(ex.ToString());
//MessageBox.Show("/nDone");
}
2311

被折叠的 条评论
为什么被折叠?



