• 自己学学泛型。


    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只能在运行时才能发现错误,导致异常,虽然泛型失去了一些灵活性,但是安全第一!
  • 相关阅读:
    激活函数
    深度学习各种环境问题积累
    读研期间如何确定论文方向?欢迎批评
    英文论文如何看?转自知乎
    最小函数依赖
    范式
    数据库中的无损连接分解和是否保持函数依赖的判定
    无损连接性、保持函数依赖1
    用CMD杀死进程
    读取properties文件
  • 原文地址:https://www.cnblogs.com/huoxingren/p/641057.html
Copyright © 2020-2023  润新知