惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
Microsoft Security Blog
Microsoft Security Blog
Recent Announcements
Recent Announcements
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Last Week in AI
Last Week in AI
罗磊的独立博客
腾讯CDC
云风的 BLOG
云风的 BLOG
月光博客
月光博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
宝玉的分享
宝玉的分享
U
Unit 42
I
InfoQ
D
DataBreaches.Net
Blog — PlanetScale
Blog — PlanetScale
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
V2EX
美团技术团队
IT之家
IT之家
Stack Overflow Blog
Stack Overflow Blog
F
Fortinet All Blogs
GbyAI
GbyAI
S
SegmentFault 最新的问题

博客园 - peak

windows 服务器时间同步失败处理方法 利用批处理自动创建schtasks系统任务 抓取网站编码信息及内容 在线调试利器Fiddler AutoResponse jquery跨域调用WCF Base-64 字符串中的无效字符 Ie7下鼠标滚轮失效 Android 笔记二(取得根目录权限) Android 笔记一 捕获asp.net ValidationSummary 控件消息。 - peak Sql Split 函数 Rss的浏览器之痛 兼容IE,Firefox 图片即时显示 asp.net 中插入flash - peak - 博客园 迷茫 windows service 之访问权限 windows Service 之调试过程 比尔盖兹在某个大学毕业典礼上的演讲中,对毕业生提出十一项极为睿智的人生建议 MSDN上关于泛型的例子
泛型
peak · 2007-09-05 · via 博客园 - peak

泛型
一、什么是泛型?
通过泛型可以定义类型安全类,而不会损害类型安全、性能或工作效率

二、实例化泛型
1、可以使用任何类型来声明和实例化
2、申明和实例话都必须用一个特定的类型来代替一般类型T
3、例子:
//原来写法
Public class Stack
{
object[] m_Items;
public void Push(object item)
{...}
public object Pop()
{...}
}
Stack stack = new Stack();
stack.Push(1);
int number = (int)stack.Pop();

//有了泛型后
Public class Stack<T>
{
T[] m_Items;
public void Push(T item)
{...}
public T Pop()
{...}
}
Stack<int> stack = new Stack<int>();
stack.Push(1);
int number = (int)stack.Pop();

三:泛型的好处
1、一次性的开发、测试和部署代码,通过任何类型来重用它
2、编译器支持和类型安全
3、不会强行对值类型进行装箱和取消装箱,或者对引用类型进行向下强制类型转换,所以性能得到显著提高。
注:值类型大概可以提高200%,引用类型大概为100%

四:多个泛型
1、单个类型可以定义多个泛型

五:泛型别名
1、在文件头部使用using 为特定类型取别名,别名作用范围是整个文件
2、例子
using List = LinkedList<int,string>;
class ListClient
{
static void Main(string[] args)
{
List list = new List();
list.AddHead(123,"AAA");
}
}

五:泛型约束
(1)、派生约束
如:
public class LinkedList<K,T> where K:IComparable
{
T Find(K key)
{
if (str.Key.CompareTo(key) == 0)//只有实现这个接口才可比较
}
}

注意:
1、所有的派生约束必须放在类的实际派生列表之后
如:public class LinkedList<K,T>:IEnumerable<T> where K:IComparable<K>
    {...}
2、一个泛型参数上可以约束多个接口(用逗号分隔)
public class LinkedList<K,T> where K:IComparable<K>,IConvertible
3、在一个约束中最多只能使用一个基类
4、约束的基类不能是密封类或静态类
5、不能将System.Delegate或System.Array约束为基类
6、可以同时约束一个基类以及一个或多个接口,但是该基类必须首先出现在派生约束列表中。
7、C#允许你将另一个泛型参数指定为约束
public class MyClass<T,U> where T:U
{...}
8、可以自己定义基类或接口进行泛型约束
9、自定义的接口或基类必须与泛型具有一致的可见性

(2)、构造函数约束
如:
class Node <K,T> where T:new()
{
}
注意:
1、可以将构造函数的约束和派生约束结合起来,前提是构造函数的约束出现在约束列表中的最后

(3)、引用/值类型约束
1、可以使用struct约束将泛型参数约束为值类型(如int、bool、enum),或任何自定义结构
2、同样可以使用class约束将泛型参数约束为引用类型
3、不能将引用/值类型约束与基类约束一起使用,因为基类约束涉及到类
4、不能使用结构和默认构造函数约束,因为默认构造函数约束也涉及到类
5、虽然您可以使用类和默认构造函数约束,但是这样做没有任何价值
6、可以将引用/值类型约束与接口约束组合起来,前提是引用/值类型约束出现在约束列表的开头

六:泛型和强制类型转换
1、C#编译器只允许将泛型参数隐式转换到Object或约束指定的类型
如:
interface IS{...}
class BaseClass{...}
class MyClass<T> where T:BaseClass,IS
{
void SomeMethod(T t)
{
IS obj1 = t;
BaseClass obj2 = t;
object obj3 = t;
}
}
2、编译器允许你将泛型参数显示强制转换到其他任何借口,但不能将其转换到类
interface IS{...}
class SomeClass{...}
class MyClass <T> //没有约束
{
void SomeMethod(T t)
{
IS obj1 = (IS)t; //可以
SomeClass obj2 = (SomeClass)t //不可以
}
}
3、可以使用临时的Object变量,将泛型参数强制转换到其他任何类型
class SomeClass{...}
class MyClass <T>
{
void SomeMethod(T t)
{
object temp = t;
SomeClass obj = (SomeClass)temp;//可以
}
}
注意:这里只是告诉你这样写是可以的,但是要不要这样写?不要这样写,因为如果t确实没有继承SomeClass编译没错但是运行就会出错
4、解决上面强制转换问题,可以使用is和as运算符进行判断
public class MyClass<T>
{
public void SomeMethod<T t>
{
if (t is int ){...}
if (t is LinkedList<int,string>){...}
//如果泛型参数的类型是所查询的类型,则is运算符返回true
string str = t as string;
//如果这写类型兼容,则as将执行强制类型转换,否则将返回null
if (str != null){...}
LinkedList<int,string> list = t as LinkedList<int,string>;
if (list != null){...}
}
}

七:继承和泛型
1、在从泛型基类派生,可以提供类型实参,而不是基类泛型参数
public class BaseClass<T>{...}
public class SubClass:BaseClass<int>
2、如果子类是泛型,而非具体的类型实参,则可以使用子类泛型参数作为泛型基类的指定类型
public class BaseClass<TT>{...}
public class SubClass<T>:BaseClass<T>{...}
3、在使用子类泛型参数时,必须在子类级别重复在基类级别规定的任何约束
4、基类可以定义其签名使用泛型参数的虚礼方法,在重写它们时,子类必须在方法签名中提供相应的类型。
如:
public class BaseClass<T>
{
public virtual T SomeMethod()
{...}
}
public class SubClass:BaseClass<int>
{
public override int SomeMethod()
{...}
}
5、如果该子类是泛型,则它还可以在重写时使用它自己的泛型参数
public class SubClass<T>:BaseClass<T>
{
public override T SomeMethod()
{...}
}
6、你可以定义泛型接口、泛型抽象类,甚至泛型抽象方法。
7、不能对泛型参数使用+或+=之类的运算符
public class Calculator<T>
{
public T Add (T arg1,T arg2)
{
return arg1 + arg2;//错误
}
}
但是我们可以通过泛型抽象类、接口来实现在个功能,因为实现泛型抽象类、接口我们就已经明确传一个参数了,就可以执行诸如+这样的操作。

八:泛型方法
1、方法可以定义特定于其执行范围的泛型参数
public class MyClass<T>
{
public void MyMethod<X>(X x)
{...}
}
2、即使各包含类根本不使用泛型,你也可以定义方法特定的泛型参数
public class MyClass
{
public void MyMethod<T>(T t)
{...}
}
注意:该功能只使用于方法,属性,索引器只能使用在类的作用范围中定义的泛型参数。
3、调用泛型方法
MyClass obj = new MyClass();
obj.MyMethod<int>(3);
也可以这样:
MyClass obj = new MyClass();
obj.MyMethod(3); //该功能称为泛型推理
4、泛型方法也可以有自己的泛型参数约束
pubic class MyClass
{
public void SomeMethod<T>(T t) where T:IComparable<T>
{...}
}
5、子类方法实现不能重复在父级别出现的约束
public class BaseClass
{
public virtual void SomeMethod<T>(T t)where T:new()
{...}
}
pubic class SubClass:BaseClass
{
public override void SomeMethod<T>(T t)//不能再有约束
{...}
}
6、静态方法
静态方法可以定义特定的泛型参数和约束
public class MyClass<T>
{
public static T SomeMethod<X>(T t,X x)
{...}
}
int number = MyClass<int>.SomeMethod<string>(3,"AAA");
或者:int mumber = MyClass<int>.SomeMethod(3,"AAA");

九:泛型委托
1、在某个类中定义的委托可以利用该类的泛型参数
2、委托也可以定义自己的泛型参数