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;
        }
    }

泛型的协变与逆变

原文地址:https://www.cnblogs.com/kissdodog/p/2879185.html