C# in depth 2nd 读后感(四) 泛型
时间:2010-12-27 来源:菜鸟老了
姓名:泛型(这是一个很多人共同拥有的名字,貌似他们来自相同的父母)
性别:未知(由于具有高超的易容术)
父母:又小又软的家伙,曰微软(名不副实啊);
出生地:C#2.0
特征:在屁股后面总是跟着两个相互看不顺眼的小屁孩:"<"&&">";(就像五行不仅相克而且相生一样,当<和>联手时,可包容万象---来自万王之王object);
性格:对于爱情至死不渝,结婚后从不考虑离婚,即使有其他类型主动投怀送抱也坚决不从,誓死抗争。及其鄙视像ArrayList这种水性杨花的人。
下面试ArrayList和泛型(List<T>读作list of T)的性格对比:

ArrayList _list=new ArrayList();
_list.Add(10);
_list.Add("try");//由于ArrayList的Add方法的参数类型为object所以添加不同类型的参数不会出错。
foreach(string s in _list)//编译通过,但是运行时10在强制转换成string时出错
{
...
}
List<string> list=new List<string>();
list.Add("try");
list.Add(10);//编译不通过
优点:使用泛型类型可以最大限度地重用代码、保护类型的安全以及提高性能。(使用泛型可以极大的减少装箱和拆箱操作,并且可以让程序员把注意力更多的转向业务流程而不是数据类型)。
名言:用我吧!
ps:好吧 我真的不知道怎么开头。
二:泛型声明
泛型类声明如下:
class GenericClass<T> where T : class,new(){ public void GetValue<U>() { }//这个T将GenericClass<T>中的T覆盖,所以又warning。建议用其他参数U替代以免混淆。
public T GetValue()
{
T _value;
_value = data;
return _value;
}
public GenericClass(T message)
{
data = message;
}
private T data;
public override string ToString()
{
return "data :" + data;
}
}
其中,GenericClass<T>为泛型类名,T为泛型参数,where 后面定义T的约束条件。
注意GetValue<U>()里的这个U,如果把U改成T,那么编译器会提示错误。因为这个T和类声明里面的那个T是不一样的,并且在方法中会将GenericClass<T>中的T隐藏掉。
如:

定义:
class GenericClass<T>// where T : class,new()
{
public void GetValue<T>() { Console.WriteLine(typeof(T)); }
}
实现:
GenericClass<string> gc = new GenericClass<string>("try");
gc.GetValue<int>();
输出:
System.Int32
在进行泛型命名时,应避免不同泛型类型采用相同名称的命名(如上)。
三、约束条件
如上,where T 后接泛型类型的约束条件。如下式MSDN上关于泛型约束条件的说明
约束 | 说明 |
---|---|
<1>T:结构 |
类型参数必须是值类型。可以指定除 Nullable 以外的任何值类型。有关更多信息,请参见使用可空类型(C# 编程指南)。 |
<2>T:类 |
类型参数必须是引用类型,包括任何类、接口、委托或数组类型。 |
<3>T:new() |
类型参数必须具有无参数的公共构造函数。当与其他约束一起使用时,new() 约束必须最后指定。 |
<4>T:<基类名> |
类型参数必须是指定的基类或派生自指定的基类。 |
<5>T:<接口名称> |
类型参数必须是指定的接口或实现指定的接口。可以指定多个接口约束。约束接口也可以是泛型的。 |
<6>T:U |
为 T 提供的类型参数必须是为 U 提供的参数或派生自为 U 提供的参数。这称为裸类型约束。 |
其中,<1><2>两种限定条件可以不存在,但是如果存在只能有一种。并且需放在其他约束条件之前。<3>约束条件只能放在最后。<4><5><6>约束条件可以有多个。

Valid
class Sample<T> where T : class, IDisposable, new()
class Sample<T> where T : struct, IDisposable
class Sample<T,U> where T : class where U : struct, T
class Sample<T,U> where T : Stream where U : IDisposable
Invalid
class Sample<T> where T : class, struct
class Sample<T> where T : Stream, class
class Sample<T> where T : new(), Stream
class Sample<T> where T : IDisposable, Stream
class Sample<T> where T : XmlReader, IComparable, IComparable
class Sample<T,U> where T : struct where U : class, T
class Sample<T,U> where T : Stream, U : IDisposable
虽然说class Sample<T,U> where T : class where U : struct, T的约束条件使用起来很别扭,但是当T是Object或接口而U是T的派生类时,Sample<T,U>可进行实例化:
Sample<IComparable, DateTime> _sample=new Sample<Icomparable,DateTime>();
四、泛型与反射
这个比较简单,可以根据反射来获取我们实例化后的参数的类型:
如:
class TypeGeneric<T>
{
void GetTypeOfT()
{
Console.WriteLine(typeof(T));
}
}
这时,当我们的用int作为参数类型时,输出System.Int32。
ps:这篇文章写得很痛苦