现在的位置: 首页 > 综合 > 正文

自己学学泛型。

2013年06月17日 ⁄ 综合 ⁄ 共 3383字 ⁄ 字号 评论关闭
1、概念:

例子

 1using System.Collections.Generic;
 2using System.Collections;
 3namespace TestGeneric
 4{
 5    class Stack<T>
 6    {
 7        private T[] store;
 8        private int size;
 9
10        public Stack()
11        {
12            store = new T[10];
13            size = 0;
14        }

15
16        public void Push(T t)
17        {
18            store[size++= x;
19        }

20        
21        public T Pop()
22        {
23            return store[--size];
24        }

25    }

26}

原来用到的集合,栈,ArrayList之类的集合,会遇到你用的是什么类型的这个问题,从oo的来看,是存为根类型,也就是object。它可以支持各种各样的操作-通用化。在高级语言中,譬如类,他们都是托管类型,也会有轻型的值类型,譬如 int byte,当然也可以使用自己 struct 结构类型。在添加到集合时,他们都会面临转到object时的装箱类型,需要复制到数据然后包装到托管堆中。这会严重的影响性能。还有就是涉及到了安全问题,譬如可以在ArrayList中可以塞入各种类型,但是出来的时候必须要小心,它需要我们将其转换为原类型,然后才能调用它自己的方法。

有了泛型之后就会方便很多,所谓泛型,就是通过参数化类型来实现在同一份代码上操作多种数据类型,好像是“模板”,它是一种编程范式,C++ java中好像都这么个概念,它利用“参数化类型”将类型抽象化,泛型其实就是一种抽象类型-即不完整的类型,只有具体化了后才能new出一个对象。优点:达到了类型的安全,复用,更高效—不需要boxing,unboxing,更清晰的更严格的约束—在编译时检查。这是一种“类型“的多态,而virtual,override,还有重载,通过继承而实现“对象”的多态。上面的例子的多参数化,是后绑定,也就是不属于某个特定类型的Stack。它可以实例化出无数个具体类型。这就是实现了复用,软件开发最强调的就是复用,客户之间的软件拷贝是一种复用,而泛型提供了软件内部复用范式的机制。

编译过程:
1、第一次编译时,编译器只为Stack<T>类型产生“泛型版本”的IL代码与元数据,并不进行实例化,T在中间只是充当占位府。
2、JIT编译时,第一次遇到Stack<int>的时候,将用int 替换“泛型版本”的IL代码与元数据的T,进行泛型类型的实例化,当第二次遇到Stack<int>,jit就不在编译了,而是直接找到已经生成好的在内存中的类型。它在内存中动态的生成一个类型,而不是保存在已经编译好的exe或dll文件中。
3、CLR为所有的类型参数为“引用类型”的泛型产生同一份代码,但如果是值类型,CLR将为每一个不同值类型产生一份代码。因为引用类型变量本身不保存值,而是一个指针,保存的是一个32位的地址。所以在实例一个具体类型的时候就可以使用同一份代码,他们共享的是同一份泛型代码,不用去确定类型。其实也是转化成了object。这点不会优化性能,因为引用类型本身就在堆了,而所说的优化性能是指值类型不再需要装箱拆箱了。大概就是这个意思,具体就不太清楚了。
4、就是说,对于引用的泛型类型时性能是没有提高的,只是“显示的约束”而提高了类型安全性。但是在值类型的集合什么的,只要涉及到将值类型转移到托管堆中,装箱拆箱什么的,使用泛型会有提高性能的表现

特点:
c#的泛型,只支持泛型方法(泛型类,非泛型类中均可)的声明类型参数,但不支持其他成员,即本身不能在譬如泛型事件,泛型属性、索引器声明泛型类型参数。但是可以在泛型类中,使用泛型类型的参数。

约束:
基类约束
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();  //类型为S的变量可以调用F1
         T.F2();
}

接口约束
类似

构造器约束
只支持无参的构造器约束
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>    right
// C<B> c2 = new C<B>   error

值类型与引用类型约束
public struct A {...}
public class B {...}
class C<T>
         where T : struct
{
      //T在这里面试一个值类型
}
C<A> c = new C<A>();   //right
C<B> c = new C<B>();   //error

 1public class Racer
 2{
 3    private string name;
 4    public string Name
 5    {
 6        get return name; }
 7    }

 8
 9    private string car;
10    public string Car
11    {
12        get return car; }
13    }

14
15    public Racer(string name, string car)
16    {
17        this.name = name;
18        this.car = car;
19    }

20
21    public override string ToString()
22    {
23        //return base.ToString();
24        return name + " , " + car;
25    }

26}

27
28class Test
29{
30    static void Main()
31    {
32        List<Racer> racers = new List<Racer>();
33        racers.Add(new Racer("jim","BMW760Li"));
34        racers.Add(new Racer ("huoxingren","Benz500"));
35        racers.Add(new Racer("zhuhee","xiali"));
36        racers.Add(new Racer ("yanhao","Benz500"));
37
38        foreach(Racer r in racers)
39        {
40            Console.WriteLine(r.ToString());
41        }

42
43        ArrayList racers2 = new ArrayList();
44        racers2.Add(400);
45        racers2.Add(new Racer("hehe","jppe"));
46        foreach(int i in racers2)
47        {
48            Console.WriteLine(i.ToString());
49        }

50    }

51}

优点:可以明显的看到,使用泛型增强了安全性,在编译时就会检查数据类型,而传统ArrayList只能在运行时才能发现错误,导致异常,虽然泛型失去了一些灵活性,但是安全第一!

抱歉!评论已关闭.