首页 > 代码库 > C#泛型

C#泛型

委托让方法参数化,而泛型实现了类型参数化。

一、泛型类型的声明规则:

  1、在类名称后跟一对尖括号,括号中为若干个类型参数,多个类型参数之间使用逗号进行分隔,类型参数实际上是个类型占位符。如、public class MyClass<T>{},T只是个习惯,实际上用其他字母也完全可以。

  2、在类声明的主体中使用类型参数来表示应该被替代的类型,一般是方法的参数类型,返回类型,或者作为字段、属性的类型。

  示例1:

    public class MyClass<T1, T2>    {        public T1 field1;   //在类内部泛型类型还能用        public T2 field2;        public T1 GetField1()  //作为返回值        {             return field1;        }        public T2 GetField2()        {            return field2;        }        public void SetField1(T1 data)  //作为方法参数类型        {            field1 = data;        }        public void SetField2(T2 data)        {            field2 = data;        }    }

  泛型能够根据传入的不同类型,实施不同的处理。重用了代码逻辑,将类型抽象了出来。

  泛型的类型约束,通过约束能够对类型实参添加一定的限制条件,约束是通过使用上下文关键字的where应用的,只需要在泛型类型声明的尖括号后面使用where关键字,后面紧跟类型参数和约束类型,中间使用冒号分隔即可。

  类型约束一共有6种,如下所示:

约束类型说明
where T : class类型实参必须是引用类型,包括任何类、接口、委托或数组类型
where T : struct类型实参必须是值类型,可以是任何值类型,但不包括Nullable
where T : <基类名>类型必须是指定的类或者它的派生类
where T : <接口名>类型必须是实现了指定的接口或者实现了该接口的类型,可以指定多个接口约束,约束接口也可以是泛型的
where T : new()类型实参必须有一个无参数的公共构造函数
where T : U类型实参T必须是类型实参U,或者是U的派生类,这称作裸类型约束

 

  同时还必须要注意,当需要添加多个类型约束时,约束之间用逗号分隔。同时对于某一个类型参数的多种约束类型,where字句与where字句之间没有次序要求,但是对于where字句内部是有次序要求的。具体次序如下:

  1.   如果有class,struct,基类这三种类型约束,则必须放在第一位。
  2.   之后是接口约束,数量不限
  3.   如果有new(),则必须放在最后。

  如:

    public class TestType<T,V> where T : Person where V : new(){} //where与where字句没有次序要求    public class TestType<T> where T : class,IList,new(){}      //where字句内部有类型要求

 

    class Program    {        static void Main(string[] args)        {            Person P = new Person();            P.Id = 1;            P.Name = "张三";            TestType<Person> tt = new TestType<Person>();            string str = tt.getType(P);            Console.WriteLine(str);     //输出张三            Console.ReadKey();        }    }    public class TestType<T> where T : Person  //指定实参类型必须是Person类或Person类的派生类    {        public string getType(T data)        {            return data.Name;        }    }    public class Person    {        public int Id;        public string Name;    }

 泛型方法与泛型类很相似。一下给出两个泛型方法的例子。

    class Program    {        static void Main(string[] args)        {            Person p = new Person();            p.Id = 1;            SetName<Person>(p);            Console.WriteLine(p.Name);  //输出张飞            Console.ReadKey();        }        public static Person SetName<T>(T per) where T : Person        {            per.Name = "张飞";            return per;        }    }    class Person    {        public int Id { get; set; }        public string Name { get; set;  }    }    class Program    {        static void Main(string[] args)        {            string str = "你好!";            Console.WriteLine(GetMessage<string>(str));     //输出System.String            Console.ReadKey();        }        public static Type GetMessage<T>(T Message)        {            return Message.GetType();        }    }    

 泛型的扩展方法,与扩展方法一样,只是有点怪异罢了。给个示例:

    class Program    {        static void Main(string[] args)        {            Person<string> per = new Person<string>();            per.Person<string>("关羽");   //这样子来调用扩展方法,自己都看不懂牛得一B            Console.WriteLine(per.Name);            Console.ReadKey();        }    }    public static class Set    {        public static void Person<T>(this Person<T> p, T Name)        {            p.Name = Name;        }            }    public class Person<T>    {        public int Id { get; set; }        public T Name { get; set; }    }

泛型委托和非泛型委托也很相似,只是泛型委托进行了一层抽象,将中间涉及的操作类型以及返回值类型抽象为了类型参数,以便更大限度地复用该委托。 

    public delegate T PrintDelegate<T>(T data);    class Program    {        static void Main(string[] args)        {            PrintDelegate<string> StrDelegate = PString; //委托的定义中,3个大T都是string            string outStr = StrDelegate("我是一个兵");   //调用委托            Console.WriteLine(outStr);         //输出委托返回值    我是一个兵我是一个兵            PrintDelegate<int> IntDelegate = PInt;  //类型参数传入int,则参数类型,返回值类型,都是int            int outInt = PInt(3);   //由于参数类型设为了int,因此只能绑定参数跟返回值为int的方法            Console.WriteLine(outInt);  //输出    6            Console.ReadKey();        }        public static string PString(string str)        {            return str + str;        }        public static int PInt(int i)        {            return i + i;        }    }

泛型的协变与逆变