在项目中通过对项目不断更深的认识运用了设计模式就难免不运到开箱和装箱操作通常的开箱和装箱操作对系统的性能有一定的影响为了解决这一个问题其中一种解决方案是运用泛型来解决下面是C#泛型的简单介绍和使用便于在项目中灵活运用
一C#泛型演示
class Stack<T>
{
private T[] store;
private int size;
public Stack()
{store = new T[]; size = ;}
public void Push(T x)
{store[size++] = x; }
public T Pop()
{return store[size];}
}
二C# 泛型简介
Stack<int> x = new Stack<int>();
xPush();
所谓泛型即通过参数化类型来实现在同一份代码上操作多种数据类型泛型编程是一种编程范式它利用参数化类型将类型抽象化从而实现更为灵活的复用C#泛型赋予了代码更强的类型安全更好的复用更高的效率更清晰的约束
三C#泛型机制简介
C#泛型能力由CLR在运行时支持区别于C++的编译时模板机制和Java的编译时茶匙发这使得泛型能力可以在各个支持CLR的语言之间进行无缝互操作C#泛型代码在被编译为IL代码和元数据时采用特殊的占位符来表示泛型类型并用专有的IL指 令支持泛型操作而真正的泛型实例化工作以 ondemand 的方式发生在JIT编译时
四C#泛型编译机制
一轮编译时编译器只为Stack<T>类型产生泛型版的IL代码与元数据——并不进行泛型类型的实例化T在中间只充当占位符JIT编译时当JIT编译器第一次遇到Stack<int>时将用int替换泛型版IL代码与元数据中的T——进行泛型类型的实例化CLR为所有类型参数为引用类型的泛型类型产生同一份代码但如果类型参数为值类型对每一个不同的值类型CLR将为其产生一份独立的代码
五C#泛型的几个特点
如果实例化泛型类型的参数相同那么JIT编译器会重复使用该类型因此C#的动态泛型能力避免了C++静态模板可能导致的代码膨胀的问题
C#泛型类型携带有丰富的元数据因此C#的泛型类型可以应用于强大的反射技术
C#的泛型采用基类 接口 构造器 值类型/引用类型的约束方式来实现对类型参数的 显式约束提高了类型安全的同时也丧失了C++模板基于签名的隐式约束所具有的高灵活性
六C#泛型类与结构
class C<U V> {} //合法
class D: C<stringint>{} //合法
class E<U V>: C<U V> {} //合法
class F<U V>: C<string int> {} //合法
class G : C<U V> { } //非法
C#除可单独声明泛型类型(包括类与结构)外也可在基类中包含泛型类型的声明但基类如果是泛型类它的类型参数要么已实例化要么来源于子类(同样是泛型类型)声明的类型参数
七泛型类型的成员
class C<V>{
public V f; //声明字段
public D<V> f; //作为其他泛型类型的参数
public C(V x) {
thisf = x;
}
}
泛型类型的成员可以使用泛型类型声明中的类型参数但类型参数如果没有任何约束则只能在该类型上使用从SystemObject继承的公有成员
八泛型接口
interface IList<T> {
T[] GetElements();
}
interface IDictionary<KV> {
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) { }
}
九泛型委托
delegate bool Predicate<T>(T value);
class X {
static bool F(int i) {}
static bool G(string s) {}
static void Main() {
Predicate<string> p = G;
Predicate<int> p = new Predicate<int>(F);
}
}
十泛型方法
支持在委托返回值和参数上应用参数类型这些参数类型同样可以附带合法的约束
泛型方法简介
C#泛型机制只支持 在方法声明上包含类型参数——即泛型方法
C#泛型机制不支持在除方法外的其他成员(包括属性事件索引器构造器析构器)的声明上包含类型参数但这些成员本身可以包含在泛型类型中并使用泛型类型的类型参数泛型方法既可以包含在泛型类型中也可以包含在非泛型类型中
十一泛型方法的声明与调用
public class Finder {
// 泛型方法的声明
public static int Find<T> ( T[] items T item) {
for(int i=;i<itemsLength;i++){
if (items[i]Equals(item)) { return i; }
}
return ;
}
}
// 泛型方法的调用
int i=FinderFind<int> ( new int[]{} );
十二泛型方法的重载
class MyClass {
void F<T>(T[] a int i); // 不可以构成重载方法
void F<U>(U[] a int i);
void F<T>(int x); //可以构成重载方法
void F(int x);
void F<T>(T t) where T : A; //不可以构成重载方法
void F<T>(T t) where T : B;
}
十三泛型方法的重写
abstract class Base
{
public abstract T F<TU>(T t U u) where U: T;
public abstract T G<T>(T t) where T: IComparable;
}
class Derived: Base{
//合法的重写约束被默认继承
public override X F<XY>(X x Y y) { }
//非法的重写指定任何约束都是多余的
public override T G<T>(T t) where T: IComparable {}
}
十四泛型约束简介
C#泛型要求对所有泛型类型或泛型方法的类型参数的任何假定都要基于显式的约束以维护C#所要求的类型安全显式约束由where子句表达可以指定基类约束接口约束构造器约束值类型/引用类型约束共四种约束显式约束并非必须如果没有指定显式约束泛型类型参数将只能访问SystemObject类型中的公有方法
十五基类约束
class A { public void F() {?} }
class B { public void F() {?} }
class C<ST>
where S: A // S继承自A
where T: B // T继承自B
{
// 可以在类型为S的变量上调用F
// 可以在类型为T的变量上调用F
}
十六接口约束
interface IPrintable { void Print(); }
interface IComparable<T> { int CompareTo(T v);}
interface IKeyProvider<T> { T GetKey(); }
class Dictionary<KV>
where K: IComparable<K>
where V: IPrintable IKeyProvider<K>
{
// 可以在类型为K的变量上调用CompareTo
// 可以在类型为V的变量上调用Print和GetKey
}
十七构造器约束
class A {
class B {
class C<T>
{
public A() { } }
public B(int i) { } }
}
C<B> c=new C<B>(); //错误B没有无参构造器
where T : new()
//可以在其中使用T t=new T();
?
C<A> c=new C<A>(); //可以A有无参构造器
十八值类型/引用类型约束
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是一个引用类型