泛型001

 

泛型简介

    所谓泛型:即通过参数化类型来实现在同一份代码上操作多种数据类型。泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。

    C#泛型赋予了代码更强的类型安全,更好的复用,更高的效率,更清晰的约束。

C#泛型机制简介

    C#泛型能力由CLR在运行时支持,区别于C++的编译时模板机制,和java的编译时的“搽拭法”。这使得泛型能力可以在各个支持CLR的语言之间进行无缝的互操作。

    C#泛型代码在被编译为IL和元数据时,采用特殊的占位符来表示泛型类型,并用专有的IL指令支持泛型操作。而真正的泛型实例化工作以“on-demand”的方式,发生在JIT编译时。

C#泛型编译机制

    第一轮编译时,编译器只为Stack<T>类型产生“泛型版”的IL代码和元数据,并不进行泛型类型的实例化,T在中间只充当占位符。

    JIT编译时,当JIT编译器第一次遇到Stack<int>时,将用int类型替换“泛型版”IL代码与元数据中的T -- 进行泛型类型的实例化。

    CLR为所有类型参数为“引用类型”的泛型类型产生同一份代码,但如果类型参数为“值类型”,对每一个不同的“值类型”,CLR将为其产生一份独立的代码。

C#泛型的几个特点

    如果实例化泛型类型的参数相同,那么JIT编译器会重复使用该类型,因此C#的动态泛型能力避免了C++静态模板可能导致的代码膨胀的问题。

    C#泛型类型携带有丰富的元数据,因此C#的泛型类型可以应用于强大的反射技术。

    C#的泛型采用“基类、接口、构造器、值类型/引用类型”的约束方式来实现对类型参数的“显示约束”,提高了类型安全的同时,也丧失了C++模板基于“签名”的隐式约束所具有的高灵活性。

我们定义了一个泛型类,那么如何实现泛型类的继承呢?这里需要满足下面两点中的任何一点即可:
1、泛型类继承中,父类的类型参数已被实例化,这种情况下子类不一定必须是泛型类;
2、父类的类型参数没有被实例化,但来源于子类,也就是说父类和子类都是泛型类,并且二者有相同的类型参数;

 

总结

    C#的泛型支持包括类,结构,接口,委托共四种泛型类型,以及方法成员.

 

 

Code

 

 

    //如果这样写的话,显然会报找不到类型T,S的错误
    public class TestChild : Test<T, S> { }

    
//正确的写法应该是
    public class TestChild : Test<stringint>{ }

    
public class TestChild<T, S> : Test<T, S> { }

    
public class TestChild<T, S> : Test<String, int> { }


接着我们来看看泛型接口,其创建以及继承规则和上面说的泛型类是一样的,看下面的代码:

    public interface IList<T> 
    
{
        T[] GetElements();
    }
 
    
public 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) 
        

        }

    }


在来看一下泛型委托,首先我们定义一个类型参数为T的委托,然后在类中利用委托调用方法:

using System;
using
 System.Collections.Generic;
using
 System.Text;

namespace
 GenericTest
{
    
//
定义一个委托,类型参数为T,返回值类型T
    
//泛型委托支持在返回值和参数上应用类型参数

    delegate string GenericDelete<T>(T value);

    
class
 test
    
{
        
static string F(int i) return "SHY520"; }

        
static string G(string s) return "SHY520"; }

        
static void Main(string[] args)
        
{
            GenericDelete
<string> G1 =
 G;
            GenericDelete
<int> G2 = new GenericDelete<int>
(F);
        }

    }
 
}


        我们再来看泛型方法,C#的泛型机制只支持在方法申明上包含类型参数,也即是泛型方法。特别注意的是,泛型不支持在除了方法以外的其他类/接口成员上使用类型参数,但这些成员可以被包含在泛型类型中,并且可以使用泛型类型的类型参数。还有一点需要说的就是,泛型方法可以在泛型类型中,也可以存在于非泛型类型中。下面我们分别看一下泛型类型的申明,调用,重载和覆盖。

using System;
using
 System.Collections.Generic;
using
 System.Text;

namespace
 GenericTest
{
    
class
 GenericClass
    
{
        
//申明一个泛型方法

        public T getvalue<T>(T t)
        
{
            
return
 t;
        }


        
//调用泛型方法
        
//注意:在调用泛型方法时,对泛型方法的类型参数实例化

        public int useMethod()
        
{
            
return this.getvalue<int>(10
);
        }


        
//重载getvalue方法
        public int getvalue(int i)
        
{
            
return
 i;
        }

    }


    
//下面演示覆盖
    
//要注意的是,泛型方法被覆盖时,约束被默认继承,不需要重新指定约束关系

    abstract class Parent
    
{
        
public abstract K TEST<K, V>
(K k, V v) where K : V;

    }


    
class Child : Parent
    
{
        
public override T TEST<T, S>
(T t, S s)
        
{
            
return
 t;
        }

    }

}


        最后我们来看一下泛型中的约束:
        C#中的泛型只支持显示的约束,因为这样才能保证C#所要求的类型安全,但显示的约束并非时必须的,如果不加约束,泛型类型参数将只能访问System.Object类型中的公有方法。“显式约束”由where子句表达,可以指定“基类约束”,“接口约束”,“构造器约束”,“值类型/引用类型约束”共四种约束。下面的例子来源于李建忠老师的讲座PPT。
1、基类约束:

    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,
    
// 可以在类型为T的变量上调用F2 

    }
 


2、接口约束

    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的变量上调用CompareTo, 
    
// 可以在类型为V的变量上调用Print和GetKey 

    }


3、构造器约束

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没有无参构造器


4、值/引用类型约束

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是一个引用类型

 

http://www.microsoft.com/china/msdn/events/webcasts/shared/webcast/episode.aspx?newsID=1242246

posted on 2008-11-07 10:57  http  阅读(224)  评论(0)    收藏  举报

导航