• 【C#进阶学习】泛型


    一、泛型引入

      需求:传入一个类型(整型/日期/字符串或其他),打印出它的类型和内容。  

     1.初级版

     1     public class CommonMethod
     2     {
     3         /// <summary>
     4         /// 打印int值
     5         /// </summary>
     6         /// <param name="iParameter"></param>
     7         public static void ShowInt(int iParameter)
     8         {
     9             Console.WriteLine("This is {0},parameter={1},type={2}",
    10                 typeof(CommonMethod).Name, iParameter.GetType().Name, iParameter);
    11         }
    12 
    13         /// <summary>
    14         /// 打印string值
    15         /// </summary>
    16         /// <param name="sParameter"></param>
    17         public static void ShowString(string sParameter)
    18         {
    19             Console.WriteLine("This is {0},parameter={1},type={2}",
    20                 typeof(CommonMethod).Name, sParameter.GetType().Name, sParameter);
    21         }
    22 
    23         /// <summary>
    24         /// 打印DateTime值
    25         /// </summary>
    26         /// <param name="dParameter"></param>
    27         public static void ShowDateTime(DateTime dParameter)
    28         {
    29             Console.WriteLine("This is {0},parameter={1},type={2}",
    30                 typeof(CommonMethod).Name, dParameter.GetType().Name, dParameter);
    31         }
    32     }
    View Code

     typeof和gettype的区别

    调用

     1         static void Main(string[] args)
     2         {
     3             DateTime dt = DateTime.Now;
     4             int i = 5;
     5             string test = "test";
     6             object o = new object();
     7             CommonMethod.ShowDateTime(dt);
     8             CommonMethod.ShowInt(i);
     9             CommonMethod.ShowString(test);
    10         }
    View Code

    2.升级版

     1         /// <summary>
     2         /// 打印object值
     3         /// 1.object是一切类型的基础
     4         /// 2.通过集成,子类拥有父类的一切属性和行为
     5         /// </summary>
     6         /// <param name="o"></param>
     7         public static void ShowObject(object oParameter)
     8         {
     9             Console.WriteLine("This is {0},parameter={1},type={2}",
    10                 typeof(CommonMethod).Name, oParameter.GetType().Name, oParameter);
    11         }
    View Code

     调用

    1             DateTime dt = DateTime.Now;
    2             int i = 5;
    3             string test = "test";
    4             object o = new object();
    5             CommonMethod.ShowObject(dt);
    6             CommonMethod.ShowObject(i);
    7             CommonMethod.ShowObject(test);
    8             CommonMethod.ShowObject(o);
    View Code

     缺点:如果传递的是值类型,会装箱拆箱

    二、泛型来喽

    定义泛型

     1     public class GenericMethod
     2     {
     3         /// <summary>
     4         /// 方法名字后面带上尖括号 类型参数
     5         /// T可以换成其他任何未定义的名称,但是不要用关键字、类名等等
     6         /// 来自 .net framework2.0 CLR升级的
     7         /// 解决相同内容/操作,对于不同参数的问题
     8         /// 
     9         /// 延迟声明,声明方法的时候没有指定参数类型,而是等到调用的时候指定
    10         /// 延迟思想:推迟一切可以推迟的
    11         /// 
    12         /// 编译的时候  类型参数编译为占位符   `(1旁边英文输入状态)
    13         /// 程序运行的时候,jit即时编译替换为真实类型
    14         /// 
    15         /// 
    16         /// </summary>
    17         /// <param name="o"></param>
    18         public static void Show<T>(T tParameter)
    19         {
    20             Console.WriteLine("This is {0},parameter={1},type={2}",
    21                 typeof(CommonMethod).Name, tParameter.GetType().Name, tParameter);
    22         }
    23     }
    View Code

    调用

    1             GenericMethod.Show<DateTime>(dt);
    2             GenericMethod.Show(dt);//不指定类型参数,编译器自动推算(编译器的语法糖)
    3             GenericMethod.Show<int>(i);
    4             GenericMethod.Show<string>(test);
    5             GenericMethod.Show<object>(o);
    View Code

    三、消耗时间对比

     1 using System;
     2 using System.Diagnostics;
     3 
     4 namespace MyGeneric
     5 {
     6     public class Monitor
     7     {
     8         public static void Show()
     9         {
    10             Console.WriteLine("******************Monitor****************");
    11             int iValue = 123456;
    12             long commonSecond = 0;
    13             long objectSecond = 0;
    14             long genericSecond = 0;
    15             
    16             {
    17                 Stopwatch watch = new Stopwatch();
    18                 watch.Start();
    19                 for (int i = 0; i < 100000000; i++)
    20                 {
    21                     ShowInt(iValue);
    22                 }
    23                 watch.Stop();
    24                 commonSecond = watch.ElapsedMilliseconds;
    25             }
    26 
    27             {
    28                 Stopwatch watch = new Stopwatch();
    29                 watch.Start();
    30                 for (int i=0;i<100000000;i++)
    31                 {
    32                     ShowObject(iValue);
    33                 }
    34                 watch.Stop();
    35                 objectSecond = watch.ElapsedMilliseconds;
    36             }
    37             {
    38                 Stopwatch watch = new Stopwatch();
    39                 watch.Start();
    40                 for (int i = 0; i < 100000000; i++)
    41                 {
    42                     Show(iValue);
    43                 }
    44                 watch.Stop();
    45                 genericSecond = watch.ElapsedMilliseconds;
    46             }
    47             Console.WriteLine("commonSecond={0},objectSecond={1},genericSecond={2}",
    48                 commonSecond, objectSecond, genericSecond);
    49             Console.Read();
    50         }
    51 
    52 
    53         public static void ShowInt(int iParameter)
    54         {
    55             //do nothing
    56         }
    57 
    58 
    59         public static void ShowObject(object oParameter)
    60         {
    61             //do nothing
    62         }
    63 
    64         public static void Show<T>(T tParameter)
    65         {
    66             //do nothing
    67         }
    68     }
    69 }
    View Code

     调试启动的时间如下,可以看出泛型执行的时间是最短的。

     如果更换顺序,将执行泛型的方法放到第一位的话,会出现泛型时间和普通时间一样,甚至还会比它耗费时间长的情况。

    ctrl+F5启动时间对比如下(这一块不懂,为什么普通方法要比泛型的时间快呢)

     四、泛型类

     1 using System;
     2 
     3 namespace MyGeneric
     4 {
     5     //泛型类
     6     public class GenericClass<W,Jasmine,Apple>//参数类型可以随便指定,意思就是相当于在这个类中定义了一个w的类型
     7     {
     8         public void Show(W w) { }
     9         public Jasmine Get()
    10         {
    11             return default(Jasmine);
    12         }
    13     }
    14     /// <summary>
    15     /// 泛型接口
    16     /// </summary>
    17     /// <typeparam name="T"></typeparam>
    18     public interface IStudy<T>
    19     {
    20         T Study(T t);
    21     }
    22     public delegate Everything GetHandler<Everything>();//泛型委托
    23 
    24     /// <summary>
    25     /// 普通类
    26     /// </summary>
    27     public class Child
    28        //: GenericClass<string,int,string> //指定类型参数后即可继承
    29        //:GenericClass<W, Jasmine, Apple> 这种写法是错误的,普通类不能直接继承泛型类
    30        //:IStudy<T> 普通类不能直接实现泛型接口
    31        : IStudy<string>
    32     {
    33         public string Study(string t)
    34         {
    35             throw new NotImplementedException();
    36         }
    37     }
    38 
    39 
    40     public class GenericChild<W,Jasmine, Apple>   
    41        //: GenericClass<W,Jasmine,Apple>  //泛型类可以直接继承泛型类
    42     //public class GenericChild<W, Jasmine>//等于声明了两个局部类型 W和Jasmin  
    43         //: GenericClass<W, Jasmine, string>
    44         :IStudy<W>                            //泛型类不能直接实现泛型接口
    45     {
    46         public W Study(W t)
    47         {
    48             throw new NotImplementedException();
    49         }
    50     }
    51 
    52 }
    View Code

    五、泛型约束

     1.所需模型

     1 using System;
     2 
     3 namespace MyGeneric
     4 {
     5     public class Model
     6     {
     7         public class People
     8         {
     9             public int Id { get; set; }
    10             public string Name { get; set; }
    11             public void Hi()
    12             {
    13             }
    14         }
    15 
    16         public interface ISports
    17         {
    18             void PingPang();
    19         }
    20 
    21         public interface IWork
    22         {
    23             void Work();
    24         }
    25 
    26         public class Chinese : People,ISports,IWork
    27         {
    28             public void Tradition()
    29             {
    30                 Console.WriteLine("谦虚");
    31             }
    32             public void SayHi()
    33             {
    34             }
    35 
    36             public void PingPang()
    37             {
    38                 throw new NotImplementedException();
    39             }
    40 
    41             public void Work()
    42             {
    43                 throw new NotImplementedException();
    44             }
    45         }
    46 
    47         public class Sichuan : Chinese
    48         {
    49             public string Panda { get; set; }
    50             public void Huoguo()
    51             {
    52                 Console.WriteLine("吃火锅啦");
    53             }
    54         }
    55     }
    56 
    57 }
    View Code

     2.泛型约束(基类约束)

     1 using System;
     2 using static MyGeneric.Model;
     3 
     4 namespace MyGeneric
     5 {
     6     public class Constraint
     7     {
     8         /// <summary>
     9         /// 有约束才有自由,有权利就得有义务
    10         /// 
    11         /// 1.基类约束,就可以访问基类的方法和属性(基类/子类)
    12         /// </summary>
    13         /// <typeparam name="T"></typeparam>
    14         /// <param name="tParameter"></param>
    15         public static void Show<T>(T tParameter) where T : People //基类约束
    16         {
    17             Console.WriteLine("This is {0},parameter={2},type={1}",
    18                 typeof(CommonMethod).Name, tParameter.GetType().Name, tParameter);
    19 
    20             Console.WriteLine(tParameter.Id);
    21             Console.WriteLine(tParameter.Name);
    22             tParameter.Hi();
    23         }
    24     }
    25 }
    View Code

     调用

     1             People people = new People()
     2             {
     3                 Id = 1,
     4                 Name = "张三"
     5             };
     6             Chinese chinese = new Chinese()
     7             {
     8                 Id = 2,
     9                 Name = "李四"
    10             };
    11             Sichuan sichuan = new Sichuan()
    12             {
    13                 Id = 3,
    14                 Name = "小红"
    15             };
    16 
    17             Constraint.Show(people);
    18             Constraint.Show(chinese);
    19             Constraint.Show(sichuan);
    View Code

       3.泛型约束(接口约束)

    1         public static void ShowSports<T>(T tParameter) where T : ISports //基类约束
    2         {
    3             Console.WriteLine("This is {0},parameter={2},type={1}",
    4                 typeof(CommonMethod).Name, tParameter.GetType().Name, tParameter);
    5 
    6             tParameter.PingPang();
    7         }
    View Code

      调用和上面的相同,实现了该接口的类,可直接当做参数传入。

     4.其他泛型约束写法

    1         public static T Get<T>()
    2             //where T:class //引用类型约束
    3             //where T:struct//值类型约束
    4             where T:new() //无参数构造函数约束
    5         {
    6             T t = new T();
    7             return default(T);
    8         }
    View Code

     六、协变

      1.相关模型(Sparrow是Bird的子类)

    1         public class Bird
    2         {
    3         }
    4 
    5         public class Sparrow : Bird
    6         {
    7         }
    View Code

      2.

    1         Bird bird1 = new Bird();
    2         //左边父类,右边子类
    3         Bird bird2 = new Sparrow();
    4         Sparrow sparrow1 = new Sparrow();
    5         List<Bird> birdList1 = new List<Bird>();
    6         //List<Bird> bird3 = new List<Sparrow>();   //不是父子关系,没有继承关系
    7 
    8         List<Bird> birdlist2 = new List<Sparrow>().Select(s => (Bird)s).ToList();
    View Code

       3.查看IEnumerable定义,可以看到有一个关键字out

        4.下面可实现左边是父类,右边是子类

    1         //协变
    2         IEnumerable<Bird> birdList4 = new List<Bird>();
    3         IEnumerable<Bird> birdList5 = new List<Sparrow>();//协变
    View Code

        5.具体应用

     1 /// <summary>
     2     /// out协变  只能是返回值
     3     /// 协变逆变只存在于接口或者委托
     4     /// </summary>
     5     /// <typeparam name="T"></typeparam>
     6     public interface ICustomerListOut<out T>
     7     {
     8         T Get();
     9         //void Show(T t); // 此处错误,T不能作为传入参数
    10     }
    11 
    12     /// <summary>
    13     /// 类没有协变逆变
    14     /// </summary>
    15     /// <typeparam name="T"></typeparam>
    16     public class CustomerListOut<T> : ICustomerListOut<T>
    17     {
    18         public T Get()
    19         {
    20             return default(T);
    21         }
    22     }
    View Code

      调用

    1         ICustomerListOut<Bird> customerList = new CustomerListOut<Bird>();
    2         ICustomerListOut<Bird> customerList1 = new CustomerListOut<Sparrow>(); //协变
    View Code

     七、逆变

     1.定义

     1     public interface ICustomerListIn<in T>
     2     {
     3         //T Get();
     4 
     5         void Show(T t);
     6     }
     7 
     8     /// <summary>
     9     /// 逆变 只能作为参数传入
    10     /// </summary>
    11     /// <typeparam name="T"></typeparam>
    12     public class CustomerListIn<T> : ICustomerListIn<T>
    13     {
    14         //T Get(); //不能作为返回值
    15 
    16         public void Show(T t)
    17         {
    18         }
    19     }
    View Code

       2.调用

    1 //逆变
    2             ICustomerListIn<Sparrow> customerList2 = new CustomerListIn<Sparrow>();
    3             ICustomerListIn<Sparrow> customerList3 = new CustomerListIn<Bird>(); //左边是子类的时候,右边可以是父类
    4 
    5             ICustomerListIn<Bird> birdList6 = new CustomerListIn<Bird>();
    6             birdList6.Show(new Sparrow());
    7             birdList6.Show(new Bird());
    View Code

      八、协变逆变混合应用

      1.定义

     1     public interface IMyList<in inT, out outT>
     2     {
     3         void Show(inT t);
     4         outT Get();
     5         outT Do(inT t);  //out只能是返回值  in只能是参数
     6     }
     7 
     8     public class MyList<T1, T2> : IMyList<T1, T2>
     9     {
    10 
    11         public void Show(T1 t)
    12         {
    13             Console.WriteLine(t.GetType().Name);
    14         }
    15         public T2 Get()
    16         {
    17             Console.WriteLine(typeof(T2).Name);
    18             return default(T2);
    19         }
    20         public T2 Do(T1 t)
    21         {
    22             Console.WriteLine(t.GetType().Name);
    23             Console.WriteLine(typeof(T2).Name);
    24             return default(T2);
    25         }
    26     }
    View Code

         2.调用

    1             IMyList<Sparrow, Bird> myList1 = new MyList<Sparrow, Bird>();
    2             IMyList<Sparrow, Bird> myList2 = new MyList<Sparrow, Sparrow>();   //协变
    3             IMyList<Sparrow, Bird> myList3 = new MyList<Bird, Bird>();   //逆变
    4             IMyList<Sparrow, Bird> myList4 = new MyList<Bird, Sparrow>();   //逆变
    View Code

       九、泛型缓存

       不太懂,有时间再好好研究下(捂脸......)

  • 相关阅读:
    示例vue 的keep-alive缓存功能的实现
    解析Vue.js中的computed工作原理
    CentOS7.2 问题收集 查看文件大小 查看端口
    Docker 配置阿里云镜像加速器
    CentOS7.2中systemctl的使用
    CentOS7.2 安装Docker
    Java 多线程中的任务分解机制-ForkJoinPool,以及CompletableFuture
    IntelliJ IDEA 在运行web项目时部署的位置
    Mysql相关问题收集
    Java命令使用 jmap,jps,jstack,jstat,jhat,jinfo
  • 原文地址:https://www.cnblogs.com/jas0203/p/10383606.html
Copyright © 2020-2023  润新知