控件中国网现已改版,您看到的是老版本网站的镜像,系统正在为您跳转到新网站首页,请稍候.......
中国最专业的商业控件资讯网产品咨询电话:023-67870900 023-67871946
产品咨询EMAIL:SALES@COMPONENTCN.COM

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

作者:未知 出处:cnblog 2013年12月05日 阅读:

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

      C#泛型参数化了类型,把类型作为参数抽象出来,从而使我们在实际的运用当中能够更好的实现代码的重复利用,同时它提供了更强的类型安全,更高的效率,不过在约束方面,它只支持显示的约束,这样在灵活性方面就显得不是那么好了。我觉得它之所以能够提供更高的效率是因为泛型在实例化的时候采用了"on-demand"的模式,即按需实例化,发生在JIT(Just In Time)编译时。

     下面来看如何定义一个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://www.cnblogs.com/jara
    /// < /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());
        }
    }
}

     上面的例子不是很恰当,目的是让初学泛型的你了解一下泛型的定义及实例化方法,如上,我们定义了一个泛型类,那么如何实现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> { }

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


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

在来看一下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);
        }
    }
}

     我们再来看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;
        }
    }
}

     最后我们来看一下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是一个引用类型
 

热推产品

  • ActiveReport... 强大的.NET报表设计、浏览、打印、转换控件,可以同时用于WindowsForms谀坔攀戀Forms平台下......
  • AnyChart AnyChart使你可以创建出绚丽的交互式的Flash和HTML5的图表和仪表控件。可以用于仪表盘的创......
首页 | 新闻中心 | 产品中心 | 技术文档 | 友情连接 | 关于磐岩 | 技术支持中心 | 联系我们 | 帮助中心 Copyright-2006 ComponentCN.com all rights reserved.重庆磐岩科技有限公司(控件中国网) 版权所有 电话:023 - 67870900 传真:023 - 67870270 产品咨询:sales@componentcn.com 渝ICP备12000264号 法律顾问:元炳律师事务所 重庆市江北区塔坪36号维丰创意绿苑A座28-5 邮编:400020
在线客服
在线客服系统
在线客服
在线客服系统