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

来源:互联网 发布:sql一行多列 sum 求和 编辑:程序博客网 时间:2024/05/15 23:49

本文转载自:http://blog.csdn.net/yl2isoft/article/details/12257249        http://www.cnblogs.com/jara/p/3458583.html

一、什么是泛型?

泛型(Generic) 允许你延迟编写类或方法中的编程元素的数据类型的规范,直到实际在程序中使用它的时候。换句话说,泛型允许您编写一个可以与任何数据类型一起工作的类或方法。你可以通过数据类型的替代参数编写类或方法的规范。当编译器遇到类的构造函数或方法的函数调用时,它会生成代码来处理指定的数据类型。

二、泛型的特性?

使用泛型是一种增强程序功能的技术,具体表现在以下几个方面:

  • 它有助于您最大限度地重用代码、保护类型的安全以及提高性能。
  • 您可以创建泛型集合类。.NET 框架类库在 System.Collections.Generic 命名空间中包含了一些新的泛型集合类。您可以使用这些泛型集合类来替代 System.Collections 中的集合类。
  • 您可以创建自己的泛型接口、泛型类、泛型方法、泛型事件和泛型委托。
  • 您可以对泛型类进行约束以访问特定数据类型的方法。
  • 关于泛型数据类型中使用的类型的信息可在运行时通过使用反射获取。
三、泛型类的声明及使用
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());        }    }}

四、泛型的继承

泛型的继承需要满足以下两点:

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

六、泛型委托

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#所要求的类型安全,但显示的约束并非时必须的。“显式约束”由where子句表达,可以指定“基类约束”,“接口约束”,“构造器约束”,“值类型/引用类型约束”共四种约束。

以下为各种约束例子:

[csharp] view plain copy
  1. class MyList<T>   
  2. {  
  3.     List<T> list = new List<T>();  
  4.     public T this[int i]  
  5.     {  
  6.         get { return list[i]; }  
  7.         set { this.list[i] = value; }  
  8.     }  
  9. }  
  10.   
  11. class Person  
  12. {  
  13.     public string Name { getset; }  
  14. }  

1 指定泛型参数为值类型

[csharp] view plain copy
  1. class MyList<T> where T:struct  
  2. {  
  3. ...代码省略部分  
  4. }  

看看加上约束后的效果怎么样,按下面方式实例化MyList

[csharp] view plain copy
  1. MyList<Person> list = new MyList<Person>();  

你会发现,将产生如下错误提示:

类型“GencConstraint.Person”必须是不可为 null 的值类型才能用作泛型类型或方法“GencConstraint.MyList<T>”中的参数“T”。

使用下面的方式实例化MyList,将一切正常:

[csharp] view plain copy
  1. MyList<int> list = new MyList<int>();  


 

指定泛型参数为引用类型

[csharp] view plain copy
  1. class MyList<T> where T:class   
  2. {  
  3. ...代码省略部分   
  4. }   

修改泛型约束为引用类型后,前面的错误提示消失,因为Person类是引用类型,满足泛型约束。

 

指定泛型参数有无参的公共的构造函数

[csharp] view plain copy
  1. class MyList<T> where T:new()  
  2. {  
  3. ...代码省略部分  
  4. }  

为Person类增加私有的无参构造函数,代码如下:

[html] view plain copy
  1. class Person  
  2. {  
  3.     public string Name { get; set; }  
  4.     private Person()  
  5.     {   
  6.         //do nothing  
  7.     }  
  8. }  

实例化MyList<Person>类:

[csharp] view plain copy
  1. MyList<Person> list = new MyList<Person>();  

出现编译错误,提示:

“GencConstraint.Person”必须是具有公共的无参数构造函数的非抽象类型,才能用作泛型类型或方法“GencConstraint.MyList<T>”中的参数“T”。

哈哈,约束起作用了。

 

指定泛型参数必须派生于指定基类

增加抽象类SeniorAnimal

[csharp] view plain copy
  1. abstract class SeniorAnimal//高级动物  
  2. {  
  3.     public abstract void Speak();//会说话  
  4.     public abstract void UseTool();//会使用工具  
  5. }  

指定泛型参数必须派生于基类SeniorAnimal

[csharp] view plain copy
  1. class MyList<T> where T : SeniorAnimal  
  2. {  
  3.      ...代码省略部分  
  4. }  

实例化MyList<Person>类(此时Person类还未继承自SeniorAnimal):

[csharp] view plain copy
  1. MyList<Person> list = new MyList<Person>();  

出现编译错误,提示:

不能将类型“GencConstraint.Person”用作泛型类型或方法“GencConstraint.MyList<T>”中的类型参数“T”。没有从“'GencConstraint.Person”到“GencConstraint.SeniorAnimal”的隐式引用转换。

修改代码,使Person类继承自SeniorAnimal

[csharp] view plain copy
  1. class Person : SeniorAnimal  
  2. {  
  3.     public string Name { getset; }  
  4.   
  5.     public override void Speak()  
  6.     {  
  7.         Console.WriteLine("我会说脏话!");  
  8.     }  
  9.   
  10.     public override void UseTool()  
  11.     {  
  12.         Console.WriteLine("我会用砍刀!");  
  13.     }  
  14. }  

再次编译,一切正常。

 

5 指定泛型参数必须实现指定接口

演示情况和第4点类似,就不提供演示代码了。

 

指定泛型参数必须派生于泛型类型U(裸类型约束)

[csharp] view plain copy
  1. class MyList<U> where U : SeniorAnimal  
  2. {  
  3.     List<U> list = new List<U>();  
  4.     public void ShowInfo<T>() where T : U  
  5.     {  
  6.     }  
  7. }  

 

 

另外,可以为同一泛型参数应用多个约束。



0 0