C# 泛型 大家有谁知道有好一点的学习泛型的网页么???最好给个链接....谢谢 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 http://topic.csdn.net/u/20090622/21/df7f7b8a-61cd-4c8f-a964-0fe15377523d.html 1. 泛型的引入 考虑一种普通的、提供传统 Push() 和 Pop() 方法的数据结构(例如,堆栈)。在开发通用堆栈时,您可能愿意使用它来存储各种类型的实例。在 C# 1.1 下,您必须使用基于 Object 的堆栈,这意味着,在该堆栈中使用的内部数据类型是难以归类的 Object,并且堆栈方法与 Object 交互。但是,基于 Object 的解决方案存在两个问题。第一个问题是性能。在使用值类型时,必须将它们装箱以便推送和存储它们,并且在将值类型弹出堆栈时将其取消装箱。装箱和取消装箱都会根据它们自己的权限造成重大的性能损失,但是它还会增加托管堆上的压力,导致更多的垃圾收集工作,而这对于性能而言也不太好。即使是在使用引用类型而不是值类型时,仍然存在性能损失,这是因为必须从 Object 向您要与之交互的实际类型进行强制类型转换,从而造成强制类型转换开销基于 Object 的解决方案的第二个问题(通常更为严重)是类型安全。因为编译器允许在任何类型和 Object 之间进行强制类型转换,所以您将丢失编译时类型安全。例如,以下代码可以正确编译,但是在运行时将引发无效强制类型转换异常:Stack stack = new Stack();stack.Push(1);//This compiles, but is not type safe, and will throw an exception: string number = (string)stack.Pop();您可以通过提供类型特定的(因而是类型安全的)高性能堆栈来克服上述两个问题。对于整型,可以实现并使用 IntStack,stringStack;遗憾的是,以这种方式解决性能和类型安全问题,会引起第三个同样严重的问题 — 影响工作效率。编写类型特定的数据结构是一项乏味的、重复性的且易于出错的任务。在修复该数据结构中的缺陷时,您不能只在一个位置修复该缺陷,而必须在实质上是同一数据结构的类型特定的副本所出现的每个位置进行修复。此外,没有办法预知未知的或尚未定义的将来类型的使用情况,因此还必须保持基于 Object 的数据结构。 2. 定义 所谓泛型,即通过参数化类型来实现在同一份代码上操作多种数据类型,泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。3. 机制: C#泛型能力是由CLR在运行时支持,区别于C++的编译时模板机制,和Java的编译时的“搽拭法”。这使得泛型能力可以在各个支持CLR的语言之间进行无缝的互操作。C#泛型代码在被编译为IL代码和元数据时,采用特殊的占位符来表示泛型类型,并用专有的IL指令支持泛型操作。而真正的泛型实例化工作以"on-demand"的方式,发生在JIT编译时。 第一轮编译时,编译器只为Stack<T>(栈算法)类型产生“泛型版”的IL代码与元数据-----并不进行泛型类型的实例化,T在中间只充当占位符JIT编译时,当JIT编译器第一次遇到Stack<int>时,将用int替换“泛型版”IL代码与元数据中的T---进行泛型类型的实例化。CLR为所有类型参数为“引用类型”的泛型类型产生同一份代码;但如果类型参数为“值类型”,对每一个不同的“值类型”,CLR将为其产生一份独立的代码。4. 使用泛型的好处: (1) 更加安全 在非泛型编程中,虽然所有的东西都可以作为Object传递,但是在传递的过程中免不了要进行类型转换。而类型转换在运行时是不安全的。使用泛型编程将可以减少不必要的类型转换,从而提高安全性。 (2) 效率更高 在非泛型编程中,将简单类型作为Object传递时会引起Boxing和Unboxing操作,这两个过程都是具有很大开销的。使用泛型编程就不必进行Boxing和Unboxing操作了。.NET泛型具有很好的二进制重用性。这一点得益于.NET将泛型内建在CLR之中。C++泛型和评估中Java泛型所依靠的是它们各自的编译器所提供的特性,编译器在编译泛型代码时将确切的类型展开,这就难免会出现代码膨胀的问题。而.NET的泛型代码是在运行时由JIT即时编译的,这样CLR就可以为不同类型重用大部分的即时编译代码了。C#泛型赋予了代码更强的类型安全,更好的复用,更高的效率,更清晰的约束。5. 应用 (1)泛型类 泛型类的定义: class MyGenericClass<T> { ///… } 其中T可以是任意标识符,只需要遵循通常的c#明明规则即可。泛型类可以在其定义中包含任意多个类型,他们使用逗号隔开。定义了这写类型之后就可以在类中其他地方使用它们,如成员变量的类型,方法的返回值类型等。 C#除可单独声明泛型类型(包括类与结构)外,也可在基类中包含泛型类型的声明。但基类如果是泛型类,它的类型参数要么已实例化,要么来源于子类(同样是泛型类型)声明的类型参数。class C<U, V> {} //合法class D: C<string,int>{} //合法class E<U, V>: C<U, V> {} //合法class F<U, V>: C<string, int> {} //合法class G : C<U, V> { } //非法 泛型集合类;非泛型集合类 泛型集合类ArrayList List<T>HashTable DIctionary<T>Queue Queue<T>Stack Stack<T>SortedList SortedList<T> (2)泛型方法• C#泛型机制只支持“在方法声明上包含类型参数”——即泛型方法• C#泛型机制不支持在除方法外的其他成员(包括属性、事件、索引器、构造器、析构器)的声明上包含类 型参数,但这些成员本身可以包含在泛型类型中,并使用泛型类型的类型参数• 泛型方法既可以包含在泛型类型中,也可以包含在非泛型类型中泛型方法的声明与调用//不是泛型类,是一个具体的类,这个类不需要泛型类型的实例化public class Finder {// 但是是一个泛型方法,请看泛型方法的声明,参数要求泛型化public static int Find<T> ( T[] items, T item) {for(int i=0;i<items.Length;i++){if (items[i].Equals(item)) { return i; }}return -1;}}// 泛型方法的调用<int>不是放到Finder后面,而是放在Find后面。int i=Finder.Find<int> ( new int[]{1,3,4,5,6,8,9}, 6);泛型方法的重载class MyClass {void F1<T>(T[] a, int i); // 不可以构成重载方法void F1<U>(U[] a, int i);void F2<T>(int x); //可以构成重载方法void F2(int x);//两句申明一样,where字句,T继承A,泛型参数必需要继承Avoid F3<T>(T t) where T : A; //不可以构成重载方法void F3<T>(T t) where T : B;}泛型方法的重写abstract class Base{public abstract T F<T,U>(T t, U u) where U: T;public abstract T G<T>(T t) where T: IComparable;}class Derived: Base{//合法的重写,约束被默认继承,只需要写方法的签名public override X F<X,Y>(X x, Y y) { }//非法的重写,指定任何约束都是多余的//重写的时候,不能写约束,也不添加新的约束,只能继承父类的约束。public override T G<T>(T t) where T: IComparable {}} (3)泛型接口泛型接口的类型参数要么已实例化,要么来源于实现类声明的类型参数。interface IList<T> { T[] GetElements(); } interface IDictionary<K,V> { void Add(K key, V value); }// 泛型接口的类型参数要么已实例化,// 要么来源于实现类声明的类型参数class List<T> : IList<T>, IDictionary<int, T> {public T[] GetElements() { return null; }public void Add(int index, T value) { }} (4)泛型委托 delegate bool Predicate<T>(T value);class x { static bool F(int i){..} static bool G(string s){..} static void Main() { Predicate<string> p2 = G; Predicate<int> p1 = new Predicate<int>(F); }}泛型委托支持在委托返回值和参数上应用参数类型,这些参数类型同样可以附带合法的约束。 6. 泛型约束 C#泛型要求对“所有泛型类型或泛型方法的类型参数”的任何假定,都要基于“显式的约束”,以维护C#所要求的类型安全。“显式约束”由where 子句表达,可以指定“基类约束”,“接口约束”,“构造器约束”,“值类型/引用类型约束”共4种约束。“显式约束”并非必须,如果没有指定“显式约束”,泛型类型参数将只能访问System.Object类型中的公有方法。约 束 定 义 示 例struct 类型必须是值类型 在类中,需要值类型才能起作用,例如,类中T类型的成员变量是0,表示某种含义class 类型必须是引用类型 在类中,需要引用类型才能起作用,例如,类中T类型的成员变量是null,表示某种含义base class 类型必须是基类或继承自基类 在类中,需要继承自基类的某种基本功能,才能起作用interface 类型必须是接口或实现了接口 在类中,需要接口提供的某种基本功能,才能起作用new() 类型必须有一个公共的无参构造函数 在类中,需要能实例化T类型的变量,例如在构造函数中实例化如果new()用作约束,它就必须是为类型指定的最后一个约束。基类约束class A { public void F1() {…} }class B { public void F2() {…} }class C<S,T>where S: A // S继承自Awhere T: B // T继承自B{// 可以在类型为S的变量上调用F1,// 可以在类型为T的变量上调用F2….}接口约束interface IPrintable { void Print(); }interface IComparable<T> { int CompareTo(T v);}interface IKeyProvider<T> { T GetKey(); }class Dictionary<K,V>where K: IComparable<K>where V: IPrintable, IKeyProvider<K>{// 可以在类型为K的变量上调用CompareTo,// 可以在类型为V的变量上调用Print和GetKey….}构造器约束class A { public A() { } }class B { public B(int i) { } }class C<T>where T : new(){//可以在其中使用T t=new T();….}C<A> c=new C<A>(); //可以,A有无参构造器C<B> c=new C<B>(); //错误,B没有无参构造器值类型/引用类型约束public struct A { … }public class B { … }class C<T>where T : struct{// T在这里面是一个值类型…}C<A> c=new C<A>(); //可以,A是一个值类型 C<B> c=new C<B>(); //错误,B是一个引用类型 C#2.0C#20锐利体验系列课程:泛型编程http://www.isheu.com/data_1212_2.aspx很不错哦,李建忠老师讲的,有视频还有PDF,很详细,很明白 关于设计论坛的时候,点击“发布”之后,如果点刷新,会出现很多个刚刚发布的帖子 DropDownList与数据库绑定问题 路径问题 100分求个计算打折的程序 如何判断一个COOKIES是否存在? 如何利用Detailsview,直接进入“添加”数据的页面? 请高手解答:如何获取调用当前静态类函数的类名称 高分之紧急求解:怎样把ASP。NET的程序的数据库转向Access. 数组问题,只花大哥10秒钟就能回答! 如何读取隐藏列的值? 浅析ASP.NET生成随机密码 image控件的图片更新
考虑一种普通的、提供传统 Push() 和 Pop() 方法的数据结构(例如,堆栈)。在开发通用堆栈时,您可能愿意使用它来存储各种类型的实例。在 C# 1.1 下,您必须使用基于 Object 的堆栈,这意味着,在该堆栈中使用的内部数据类型是难以归类的 Object,并且堆栈方法与 Object 交互。
但是,基于 Object 的解决方案存在两个问题。第一个问题是性能。在使用值类型时,必须将它们装箱以便推送和存储它们,并且在将值类型弹出堆栈时将其取消装箱。装箱和取消装箱都会根据它们自己的权限造成重大的性能损失,但是它还会增加托管堆上的压力,导致更多的垃圾收集工作,而这对于性能而言也不太好。即使是在使用引用类型而不是值类型时,仍然存在性能损失,这是因为必须从 Object 向您要与之交互的实际类型进行强制类型转换,从而造成强制类型转换开销
基于 Object 的解决方案的第二个问题(通常更为严重)是类型安全。因为编译器允许在任何类型和 Object 之间进行强制类型转换,所以您将丢失编译时类型安全。例如,以下代码可以正确编译,但是在运行时将引发无效强制类型转换异常:
Stack stack = new Stack();
stack.Push(1);
//This compiles, but is not type safe, and will throw an exception:
string number = (string)stack.Pop();您可以通过提供类型特定的(因而是类型安全的)高性能堆栈来克服上述两个问题。对于整型,可以实现并使用 IntStack,stringStack;
遗憾的是,以这种方式解决性能和类型安全问题,会引起第三个同样严重的问题 — 影响工作效率。编写类型特定的数据结构是一项乏味的、重复性的且易于出错的任务。在修复该数据结构中的缺陷时,您不能只在一个位置修复该缺陷,而必须在实质上是同一数据结构的类型特定的副本所出现的每个位置进行修复。此外,没有办法预知未知的或尚未定义的将来类型的使用情况,因此还必须保持基于 Object 的数据结构。
2. 定义
所谓泛型,即通过参数化类型来实现在同一份代码上操作多种数据类型,泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。
3. 机制:
C#泛型能力是由CLR在运行时支持,区别于C++的编译时模板机制,和Java的编译时的“搽拭法”。这使得泛型能力可以在各个支持CLR的语言之间进行无缝的互操作。
C#泛型代码在被编译为IL代码和元数据时,采用特殊的占位符来表示泛型类型,并用专有的IL指令支持泛型操作。而真正的泛型实例化工作以"on-demand"的方式,发生在JIT编译时。
第一轮编译时,编译器只为Stack<T>(栈算法)类型产生“泛型版”的IL代码与元数据-----并不进行泛型类型的实例化,T在中间只充当占位符
JIT编译时,当JIT编译器第一次遇到Stack<int>时,将用int替换“泛型版”IL代码与元数据中的T---进行泛型类型的实例化。
CLR为所有类型参数为“引用类型”的泛型类型产生同一份代码;但如果类型参数为“值类型”,对每一个不同的“值类型”,CLR将为其产生一份独立的代码。
4. 使用泛型的好处:
(1) 更加安全
在非泛型编程中,虽然所有的东西都可以作为Object传递,但是在传递的过程中免不了要进行类型转换。而类型转换在运行时是不安全的。使用泛型编程将可以减少不必要的类型转换,从而提高安全性。
(2) 效率更高
在非泛型编程中,将简单类型作为Object传递时会引起Boxing和Unboxing操作,这两个过程都是具有很大开销的。使用泛型编程就不必进行Boxing和Unboxing操作了。
.NET泛型具有很好的二进制重用性。这一点得益于.NET将泛型内建在CLR之中。C++泛型和评估中Java泛型所依靠的是它们各自的编译器所提供的特性,编译器在编译泛型代码时将确切的类型展开,这就难免会出现代码膨胀的问题。而.NET的泛型代码是在运行时由JIT即时编译的,这样CLR就可以为不同类型重用大部分的即时编译代码了。
C#泛型赋予了代码更强的类型安全,更好的复用,更高的效率,更清晰的约束。
5. 应用
(1)泛型类
泛型类的定义:
class MyGenericClass<T>
{
///…
}
其中T可以是任意标识符,只需要遵循通常的c#明明规则即可。泛型类可以在其定义中包含任意多个类型,他们使用逗号隔开。定义了这写类型之后就可以在类中其他地方使用它们,如成员变量的类型,方法的返回值类型等。
C#除可单独声明泛型类型(包括类与结构)外,也可在基类中包含泛型类型的声明。但基类如果是泛型类,它的类型参数要么已实例化,要么来源于子类(同样是泛型类型)声明的类型参数。
class C<U, V> {} //合法
class D: C<string,int>{} //合法
class E<U, V>: C<U, V> {} //合法
class F<U, V>: C<string, int> {} //合法
class G : C<U, V> { } //非法
泛型集合类;
非泛型集合类 泛型集合类
ArrayList List<T>
HashTable DIctionary<T>
Queue Queue<T>
Stack Stack<T>
SortedList SortedList<T> (2)泛型方法
• C#泛型机制只支持“在方法声明上包含类型参数”——即泛型方法
• C#泛型机制不支持在除方法外的其他成员(包括属性、事件、索引器、构造器、析构器)的声明上包含类 型参数,但这些成员本身可以包含在泛型类型中,并使用泛型类型的类型参数
• 泛型方法既可以包含在泛型类型中,也可以包含在非泛型类型中
泛型方法的声明与调用
//不是泛型类,是一个具体的类,这个类不需要泛型类型的实例化
public class Finder {
// 但是是一个泛型方法,请看泛型方法的声明,参数要求泛型化
public static int Find<T> ( T[] items, T item) {
for(int i=0;i<items.Length;i++){
if (items[i].Equals(item)) { return i; }
}
return -1;
}
}
// 泛型方法的调用<int>不是放到Finder后面,而是放在Find后面。
int i=Finder.Find<int> ( new int[]{1,3,4,5,6,8,9}, 6);泛型方法的重载
class MyClass {
void F1<T>(T[] a, int i); // 不可以构成重载方法
void F1<U>(U[] a, int i);
void F2<T>(int x); //可以构成重载方法
void F2(int x);
//两句申明一样,where字句,T继承A,泛型参数必需要继承A
void F3<T>(T t) where T : A; //不可以构成重载方法
void F3<T>(T t) where T : B;
}
泛型方法的重写
abstract class Base
{
public abstract T F<T,U>(T t, U u) where U: T;
public abstract T G<T>(T t) where T: IComparable;
}
class Derived: Base{
//合法的重写,约束被默认继承,只需要写方法的签名
public override X F<X,Y>(X x, Y y) { }
//非法的重写,指定任何约束都是多余的
//重写的时候,不能写约束,也不添加新的约束,只能继承父类的约束。
public override T G<T>(T t) where T: IComparable {}
}
(3)泛型接口
泛型接口的类型参数要么已实例化,要么来源于实现类声明的类型参数。
interface IList<T> {
T[] GetElements();
}
interface IDictionary<K,V> {
void Add(K key, V value);
}
// 泛型接口的类型参数要么已实例化,
// 要么来源于实现类声明的类型参数
class List<T> : IList<T>, IDictionary<int, T> {
public T[] GetElements() { return null; }
public void Add(int index, T value) { }
}
(4)泛型委托
delegate bool Predicate<T>(T value);
class x {
static bool F(int i){..}
static bool G(string s){..}
static void Main()
{
Predicate<string> p2 = G;
Predicate<int> p1 = new Predicate<int>(F);
}
}
泛型委托支持在委托返回值和参数上应用参数类型,这些参数类型同样可以附带合法的约束。 6. 泛型约束
C#泛型要求对“所有泛型类型或泛型方法的类型参数”的任何假定,都要基于“显式的约束”,以维护C#所要求的类型安全。
“显式约束”由where 子句表达,可以指定“基类约束”,“接口约束”,“构造器约束”,“值类型/引用类型约束”共4种约束。
“显式约束”并非必须,如果没有指定“显式约束”,泛型类型参数将只能访问System.Object类型中的公有方法。约 束 定 义 示 例
struct 类型必须是值类型 在类中,需要值类型才能起作用,例如,类中T类型的成员变量是0,表示某种含义
class 类型必须是引用类型 在类中,需要引用类型才能起作用,例如,类中T类型的成员变量是null,表示某种含义
base class 类型必须是基类或继承自基类 在类中,需要继承自基类的某种基本功能,才能起作用
interface 类型必须是接口或实现了接口 在类中,需要接口提供的某种基本功能,才能起作用
new() 类型必须有一个公共的无参构造函数 在类中,需要能实例化T类型的变量,例如在构造函数中实例化
如果new()用作约束,它就必须是为类型指定的最后一个约束。
基类约束
class A { public void F1() {…} }
class B { public void F2() {…} }
class C<S,T>
where S: A // S继承自A
where T: B // T继承自B
{
// 可以在类型为S的变量上调用F1,
// 可以在类型为T的变量上调用F2
….
}
接口约束
interface IPrintable { void Print(); }
interface IComparable<T> { int CompareTo(T v);}
interface IKeyProvider<T> { T GetKey(); }
class Dictionary<K,V>
where K: IComparable<K>
where V: IPrintable, IKeyProvider<K>
{
// 可以在类型为K的变量上调用CompareTo,
// 可以在类型为V的变量上调用Print和GetKey
….
}
构造器约束
class A { public A() { } }
class B { public B(int i) { } }
class C<T>
where T : new()
{
//可以在其中使用T t=new T();
….
}
C<A> c=new C<A>(); //可以,A有无参构造器
C<B> c=new C<B>(); //错误,B没有无参构造器
值类型/引用类型约束
public struct A { … }
public class B { … }
class C<T>
where T : struct
{
// T在这里面是一个值类型
…
}
C<A> c=new C<A>(); //可以,A是一个值类型
C<B> c=new C<B>(); //错误,B是一个引用类型
http://www.isheu.com/data_1212_2.aspx
很不错哦,李建忠老师讲的,有视频还有PDF,很详细,很明白