浅谈C#泛型的定义、继承、方法和约束

本文介绍了如何定义一个C#泛型类,以及实现泛型类的继承、方法和约束。

泛型类和泛型方法兼复用性、类型安全和高效率于一身,是与之对应的非泛型的类和方法所不及。泛型广泛用于容器(collections)和对容器操作的方 法中。

.NET框架2.0的类库提供一个新的命名空间System.Collections.Generic,其中包含了一些新的基于泛型的容器类。要查 找新的泛型容器类(collection classes)的示例代码,请参见基础类库中的泛型。当然,你也可以创建自己的泛型类和方法,以提供你自己的泛化的方案和设计模式,这是类型安全且高效 的

 

1.C#泛型类

下面来看如何定义一个C#泛型类,很简单,你只需要意识到一点,在这里,类型已经被参数化了:

    using System;  
    using System.Collections.Generic;  
    using System.Text;  
     
    namespace GenericTest  
    {  
     class Program  
     {  
    static void Main(string[] args)  
    {  
     //使用string,int来实例化Test< T,S>类  
     Test< string, int> t = new Test< string, int>("SHY520",22);  
     
     //调用泛型类中的方法  
     t.SetValue();  
    }  
     }  
     
     /**//// < summary>  
     /// 定义一个泛型类,该类有两个类型参数,分别是T,S  
     /// http://pw.cnblogs.com  
     /// < /summary>  
     /// < typeparam name="T">类型参数< /typeparam>  
     /// < typeparam name="S">类型参数< /typeparam>  
     public class Test< T,S>  
     {  
    //泛型类的类型参数可用于类成员  
    private T name;  
    private S age;  
     
    public Test(T Name,S Age)  
    {  
     this.name = Name;  
     this.age = Age;  
    }  
     
    public void SetValue()  
    {  
     Console.WriteLine(name.ToString());  
     Console.WriteLine(age.ToString());  
    }  
     }  
    } 

 

2.C#泛型类的继承

上面的例子不是很恰当,目的是让初学泛型的你了解一下泛型的定义及实例化方法,如上,我们定义了一个泛型类,那么如何实现C#泛型类的继承呢?这里需要满足下面两点中的任何一点即可:

1、泛型类继承中,父类的类型参数已被实例化,这种情况下子类不一定必须是泛型类;

2、父类的类型参数没有被实例化,但来源于子类,也就是说父类和子类都是泛型类,并且二者有相同的类型参数;

    //如果这样写的话,显然会报找不到类型T,S的错误  
    public class TestChild : Test< T, S> { }  
     
    //正确的写法应该是  
    public class TestChild : Test< string, int>{ }  
    public class TestChild< T, S> : Test< T, S> { }  
    public class TestChild< T, S> : Test< String, int> { } 

 

3.C#泛型接口

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

    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)   
     {}  
    } 

 

4.C#泛型委托

在来看一下C#泛型委托,首先我们定义一个类型参数为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);  
}  
 }   

 

5.C#泛型类型的申明,调用,重载和覆盖

我们再来看C#泛型方法,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;  
    }  
     }  
    } 

 

6.C#泛型中的约束

最后我们来看一下C#泛型中的约束:

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

 

posted @ 2014-08-14 15:00  Net-Spider  阅读(633)  评论(0)    收藏  举报