• 泛型编程


    泛型概述
     所谓泛型,即通过参数化类型来实现在同一份代码上操作多种数据类型。泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。C#泛型赋予了代码更强的类型安全,更好的复用,更高的效率,更清晰的约束(这个特点褒贬不一)。

    C#泛型机制简介
     A。C#泛型能力由CLR在运行时支持,区别于C++的编译时模板机制,和Java的编译时“搽拭法”。(C++所有的泛型的处理都在编译时,运行时看不到泛型。Java编译器实际上只是做了类型安全的控制,不能获得高更的效率。)这使得泛型能力可以在各个支持CLR的语言(如VB.NET)之间进行无缝的互操作。
     B。C#泛型代码在被编译为IL代码和元数据时,采用特殊的占位符来表示泛型类型,并用专有的IL指令支持泛型操作。而真正的泛型实例化工作以“on-demand”的方式(按需所取,当代码真正碰到实例化的代码时才去实例化。比如一个方法对泛型进行了实例化,但程序没有去调用这个方法,则这个实例化工作就不会发生),发生在JIT编译时。
     反编译工具路径(查看IL代码):C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\ildasm.exe

    C#泛型编译机制
     A。第一轮编译时,编译器只为Stack<T>类型产生“泛型版”的IL代码与元数据--并不进行泛型类型的实例化,T在中间只充当占位符。
     B。JIT编译时,当JIT编译器第一次遇到Stack<int>时,将用int替代“泛型版”IL代码与元数据中的T--进行泛型类型的实例化,此时T才成为一个可用的类型。(以后再遇到Stack<int>时会拿内存中存放的上次实例化过的类型,不会再实例化。但如果是新的类型,如Stack<byte>,则会再一次实例化,放到内存中。)
     C。CLR为所有类型参数为“引用类型”的泛型类型产生同一份代码;但如果类型参数为“值类型”,对每一个不同的“值类型”,CLR将为其产生一份独立的代码。

    C#泛型的几个特点
     A。如果实例化泛型的参数相同,那么JIT编译器会重复使用该类型,因此C#的动态泛型能力避免了C++静态模板可能导致的代码膨胀的问题。
     B。C#泛型类型携带有丰富的元数据,因此C#的泛型类型可以应用于强大的反射技术。
     C。C#的泛型采用“基类,接口,构造器,值类型/引用类型”的约束方式来实现对类型参数的“显式约束”,提高了类型安全的同时,也丧失了C++模板基于“签名”的隐式约束所具有的高灵活性。

    C#泛型类与结构
     class C<U,V>{} //合法
     class D:C<string,int>{} //合法(泛型类型可以作为父类被继承)
     class E<U,V>:C<U,V>{} //合法(父类C的类型参数使用了子类E的类型参数)
     class F<U,V>:C<string,int>{} //合法(父类可以不使用子类的类型参数,直接实例化)
     class G:C<U,V>{} //非法(子类是具体类型,父类是泛型类型但没有实例化。当使用G时,不用去实例化,那么C中的U和V是不确定的。所以这样定义是非法的)
     C#除可单独声明泛型类型(包括类与结构)外,也可以在基类中包含泛型类型的声明。但基类如果是泛型类,它的类型参数要么已实例化,要么来源于子类(同样是泛型类型)声明的类型参数。
     
    泛型类型的成员
     class C<V>{
      public V f1; //声明字段
      public D<V> f2; //作为其它泛型类型的参数
      public C(V x){
       this.f1 = x;
      }
     }
     泛型类型的成员可以使用泛型类型声明中的类型参数。但类型参数如果没有任何约束,则只能在该类型上使用从System.Object继承的公有成员。

    泛型接口
     interface IList<T>{
      T[] GetElements(); //泛型数组
     }
     interface IDictionary<K,V>{
      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> p2 = G; //简略写法
       Predicate<int> p1 = new Predicate<int>(F);
      }
     }
     泛型委托支持在委托返回值和参数上应用参数类型,这些参数类型同样可以附带合法的约束。

    泛型方法
     A。C#泛型机制只支持“在方法声明上包含类型参数”--即泛型方法。
     B。C#泛型机制不支持在除在方法外的其它成员(包括属性、事件、索引器、构造器、析构器)的声明上包含类型参数,但这些成员本身可以包含在泛型类型中,并使用泛型类型的类型参数。
     C。泛型方法既可以包含在泛型类型中,也可以包含在非泛型类型中。
     
    泛型方法的声明与调用
     public class Finder{
      //泛型方法的声明
      public static int Find<T> (T[] items,T item){
       for(int i=0;i<items.Length;i++){
        if(items[i].Equals(item)) { return i; }
       }
       return -1;
      }
     }
     //泛型方法的调用
     int i = Finder.Find<int> (new int[]{1,2,3,4,5},3);

    泛型方法的重载
     class MyClass{
      void F1<T>(T[] a,int i); //不可以构成重载方法(实例化时没办法区分调用的方法)
      void F1<U>(U[] a,int i);
      
      void F2<T>(int x); //可以构成重载方法
      void F2(int x);
      
      void F3<T>(T t) where T:A; //不可以构成重载方法
      void F3<T>(T t) where T:B;
     }
     
    泛型方法的重写
     abstract class Base
     {
      public abstract T F<T,U>(T t,U u) where U:T;
      public abstract T G<T>(T t) where T:IComparable;
     }
     class Derived:Base{
      //合法的重写,约束被默认继承
      public override X F<X,Y>(X x,Y y) {}
      //非法的重写,指定任何约束都是多余的(不管是重新写一遍父类的约束,又或是想添加新的约束都是不合法的)
      public override T G<T>(T t) where T:IComparable {}
     }

    泛型约束
     A。C#泛型要求对“所有泛型类型或泛型方法的类型参数”的任何假定,都要基于“显示的约束”,以维护C#所要求的类型安全。
     B。“显式约束”由where子句表达,可以指定“基类约束”,“接口约束”,“构造器约束”,“值类型/引用类型约束”共四种约束。
     C。“显式约束”并非必须,如果没有指定“显式约束”,泛型类型参数将只能访问System.Object类型中的公有方法。

    基类约束
     class A { public void F1() { ... } }
     class B { public void F2() { ... } }
     class C<S,T> where S:A where T:B //S必须继承于A,T必须继承于B
     {
      //可以在类型为S的变量上调用F1,在类型为T的变量上调用F2
     }

    接口约束
     interface IPrintable { void Print(); }
     interface IComparable<T> { int CompareTo(T v);}
     interface IKeyProvider<T> { T GetKey(); }
     class Dictionary<K,V> where K:IComparable<K> where V:IPrintable,IKeyProvider<K> //K必须实现IComparable,V必须实现IPrintable和IKeyProvider
     {
      //可以在类型为K的变量上调用CompareTo,在类型为V的变量上调用Print和GetKey
     }

    构造器约束:
     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>(); //可以,A有无参构造器
     C<B> c = new C<B>(); //错误,B没有无参构造器(因为自定义了一个构造器后C#不会自动产生一个无参构造器)

    值类型/引用类型约束:
     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是一个引用类型


    其它资料

    泛型的类型安全
     ArrayList al = new ArrayList();  //引入System.Collections
     al.Add(1);
     al.Add(2);
     //al.Add(3.0);  //加上这句,编译通过但运行出错
     int total = 0;
     foreach (int var in al)
     {
         total += var;
     }
     Console.WriteLine("Total is {0}", total);
     
     List<int> aLst = new List<int>();  //引入System.Collections.Generics
     aLst.Add(1);
     aLst.Add(2);
     //aLst.Add(3.0);  //加上这句,编译通不过
     int total2 = 0;
     foreach (int var in aLst)
     {
         total2 += var;
     }
     Console.WriteLine("Total2 is {0}", total2);


    .NET CLR识别泛型
     public class MyList<T>  //泛型类
     {
         private static int objCount = 0;
         public MyList() { objCount++; }
         public int Count
         {
             get { return objCount; }
         }
     }
     public class SampleClass
     { }
     static void Main(string[] args)
     {
         MyList<int> myIntList = new MyList<int>();
         MyList<int> myIntList2 = new MyList<int>();
         MyList<double> myDoubleList = new MyList<double>();
         MyList<SampleClass> mySampleList = new MyList<SampleClass>();
         Console.WriteLine(myIntList.Count);  //2
         Console.WriteLine(myIntList2.Count);  //2
         Console.WriteLine(myDoubleList.Count);  //1
         Console.WriteLine(mySampleList.Count);  //1
         Console.WriteLine(new MyList<SampleClass>().Count);  //2
     }

    泛型方法:
    public static void Copy<T>(List<T> source, List<T> destination)
    {
        foreach (T obj in source)
        {
            destination.Add(obj);
        }
    }
    static void Main(string[] args)
    {
        List<int> lst1 = new List<int>();
        lst1.Add(2);
        lst1.Add(4);
        List<int> lst2 = new List<int>();
        Copy(lst1, lst2);
        Console.WriteLine(lst2.Count);
    }

    泛型的意义何在:
     A。泛型可以减少重复的代码,类似的函数,如double和int型的比较函数,可以通过一个泛型方法实现。
     B。类型安全和减少装箱、拆箱(指定泛型方法/类的参数类型),并不是泛型的意义,而是泛型带来的两个最明显的好处而已。
     C。泛型的真正意义在于:把类型作为参数。它实现了代码之间的很好的横向联系(继承为代码提供了一种从上往下的纵向联系)。

  • 相关阅读:
    实验6:Mapreduce实例——WordCount
    暑期生活10
    暑期生活9
    暑期生活8
    暑期生活7
    暑期生活6
    暑期生活5
    暑期生活4
    暑期生活3
    暑期生活2
  • 原文地址:https://www.cnblogs.com/vipcjob/p/1555809.html
Copyright © 2020-2023  润新知