1 概述
1.1 定义:(1)泛型是具有占位符(类型参数)的类、结构、接口和方法(2)泛型类和泛型方法同时具备可重用性、类型安全和效率,这是非泛型类和非泛型方法无法具备的。 泛型通常用与集合以及作用于集合的方法一起使用。
1.2 泛型类库:System.Collections.Generic 和 System.Collections.ObjectModel 命名空间中提供了很多泛型集合类
1.3 使用:
public class Generic<T>
{
public T Field;
}
public static void Main()
{
Generic<string> g = new Generic<string>();
g.Field = "A string";
Console.WriteLine("Generic.Field = \"{0}\"", g.Field);
}
1.4 泛型的优点和限制
1.4.1 避免其他客户端代码使用单个类时,引入强制转换或装箱操作的成本和风险。如ArrayList为非泛型方法,在对其赋值时,实际是转换成了object类型。List<T>泛型方法灵活应用不同类型参数,不存在类型转换。
1.4.2 类型推导:int index0 = Array.BinarySearch(myArray, "test string");
int index1 = Array.BinarySearch<string>(myArray, "test string");
1.4.3 (1) .NET Framework 不支持上下文绑定的泛型类型。泛型类型可以从 ContextBoundObject 派生,但是尝试创建该类型的实例将导致 TypeLoadException。
(2)枚举不能有泛型类型参数。
1.5 术语
1.5.1 “泛型类型定义”是用作模板的类、结构或接口声明,其中具有该类、结构或接口声明可以包含或使用的类型的占位符。“泛型类型定义”是具有两个参数列表的方法:一个泛型类型参数列表和一个形参列表。
eg: 下述代码中,只有函数G是泛型类型,M不是。原因:M不具有泛型类型参数列表。)
class A
{
T G<T>(T arg) {...}
}
class Generic<T>
{
T M(T arg) {...}
}
1.5.2 “泛型类型参数”或称“类型参数”是泛型类型或方法定义中的占位符。System.Collections.Generic. Dictionary< TKey, TValue> 泛型类型具有两个类型参数: TKey 和 TValue,分别表示其键和值的类型。
1.5.3 “构造泛型类型”或称“构造类型”是为泛型类型定义的泛型类型参数指定类型得到的结果。
1.5.4 “泛型类型参数”是替换泛型类型参数的任何类型。
2.用于操作数据和列表的泛型委托
2.1 Action<T> 泛型委托表示对指定类型的元素执行某些操作的方法。泛型Action<T>委托表示引用一个void返回类型的方法。
2.2 Func<T>委托可以以类似的方式使用。Func<T>允许调用带返回类型的方法。
(1)Func<out TResult>委托类型可以调用带返回类型且无参数的方法;(2)Func<in T,out TResult>调用带一个参数和一个返回参数的方法;(3)Func<in T1,in T2,in T3,in T4,out TResult>调用带4个参数和一个返回参数的方法...
eg:
public static void Main()
{
Action<int> f1 = i => { Console.WriteLine("i={0}", i); };
f1(10);
Action<int, string> f2 =
(i, s) => { Console.WriteLine("i={0} s={1}", i, s); };
f2(99, "Hello");
Func<int, string> f4 =
i => string.Format("i={0} i+1={1}", i, i+1);
Console.WriteLine(f4(1));
}
2.2 Predicate<T> 泛型委托表示用于确定特定元素是否满足您定义的标准的方法。
2.3 Comparison<T> 泛型委托允许为没有本机排序顺序的数组或列表元素提供排序顺序或者重写本机排序顺序。
2.4 Converter<TInput, TOutput> 泛型委托允许定义两种类型之间的转换,并允许将一种类型的数组转换为另一种类型的数组,或者将一种类型的列表转换为另一种类型的列表。
3.泛型中的协变 逆变
3.1协变
IEnumerable<Derived> d = new List<Derived>();
IEnumerable<Base> b = d;
解读:父亲能分配到儿子的实例。子-->父
3.2 逆变
Action<Base> b = (target) => { Console.WriteLine(target.GetType().Name); };
Action<Derived> d = b;
d(new Derived());
解读:父亲所具有的方法能传递给儿子来调用。父-->子
4.泛型约束。“约束”是加在泛型类型参数上的限制。
(1)约束使得泛型类能够使用 Employee.Name 属性,因为类型为 T 的所有项都保证是 Employee 对象或从 Employee 继承的对象。
class EmployeeList<T> where T : Employee, IEmployee, System.IComparable<T>, new()
{
// ...
}
(2)注意:where T : class 约束时,避免对类型参数使用 == 和 != 运算符
(3)裸类型约束:用作约束的泛型类型参数称为裸类型约束。示例中,T 在 Add 方法的上下文中是一个裸类型约束.
class List<T>
{
void Add<U>(List<U> items) where U : T {/*...*/}
}