104-06-泛型

1. 本文构建思路

  1. 什么是泛型
  2. 泛型是解决什么问题的(为什么会出现泛型)?
    用一个demo说明问题:功能概述打印输出不同类型值,分别写三个方法分别实现,详见正文部分
  3. 通过这个例子用三种不同的实现方法,得出结论,泛型 是一种比较优的方法,
    泛型的其他主要应用场景
    1. 泛型集合
    2. 泛型类
    3. 泛型方法
    4. 泛型接口
    5. 泛型委托
  4. 进阶
    1. 泛型约束
    2. 逆变与协变
    3. 泛型缓存
  5. 泛型的好处与原理

2. 正文

2.1 什么是泛型
1. 理解:泛型:广泛的变量类型(类型包括:int、double等系统类型,自定义的类型(自定义类))
* 相同的处理逻辑,不同类型的参数,在处理时需要分别处理,在这种情况下,需要有一种类型可以用来替代所有类型进行逻辑  
* 设计思想:声明的时候不指定变量类型,在调用的时候再指定类型,延迟声明(将参数的类型的声明推迟到调用),理解是单身狗(遇到的时候再声明类型)与已婚男士(提前声明变量类型)的区别 ---(拓展:延迟思想) 
* 下面demo3中的泛型方法:private static void PrintPara<T>(T para) 中的T
    T:占位符,这个占位符满足C#命名规范即可,但是约定俗成用 T
    T:表示为通用数据类型,在使用的时候,用实际类型代替
2. 好处:增加类型安全,便于维护
2.2 泛型是解决什么问题的(为什么会出现泛型)?

用一个demo说明问题:功能概述打印输出不同类型值,分别写三个方法分别实现,详见正文部分

  1. 方法1:用基础方法实现(用时14ms),下面为实现代码
    #region 方法1:基础方法实现打印输出不同的数据类型      
        public static void Main(string[] args)
        {
           Stopwatch stopWatch = new Stopwatch();
           stopWatch.Start();
           PrintPara(12);
           PrintPara("123");
           PrintPara(DateTime.Now);
           stopWatch.Stop();
           Console.WriteLine(stopWatch.ElapsedMilliseconds);
           Console.ReadLine();


        }

        private static void PrintPara(int Para)
        {
           Console.WriteLine($"这个参数的类型是{Para.GetType().Name},值为{Para}");
        }
        private static void PrintPara(string Para)
        {
           Console.WriteLine($"这个参数的类型是{Para.GetType().Name},值为{Para}");
        }
        private static void PrintPara(DateTime dateTime)
        {
           Console.WriteLine($"这个值得数据类型为{dateTime.GetType().Name},值为{dateTime}");
        }
        #endregion
    评价:这样写造成代码冗余,不易维护
    解决:用Object类替代吧,原因是:
    1). Object是所有类型的基类 
    2). 根据继承的原则,所有父类出现的地方,父类均可以被子类替换
  1. 方法2:用Object方法实现(用时16ms),用一个方法即可实现,下面为实现代码
        public static void Main(string[] args)
        {
           Stopwatch stopWatch = new Stopwatch();
           stopWatch.Start();
           PrintPara(12);
           PrintPara("123");
           PrintPara(DateTime.Now);
           stopWatch.Stop();
           Console.WriteLine(stopWatch.ElapsedMilliseconds);
           Console.ReadLine();
        }
        private static void PrintPara(Object Para)
        {
           Console.WriteLine($"这个参数的类型是{Para.GetType().Name},值为{Para}");
        }       
    评价:Object 实现后,通过对比两者实现所用的时间,可以看出Object效率低
    原因是:存在  拆箱装箱 问题
    不能为了便于维护,就牺牲效率吧,那样的话,没有什么意义啊,
    有没有一种即便于维护又可以兼顾效率的写法呢?
    有!!!!
    泛型(带着音乐与光环,自己想象一下....)

注: 拆箱装箱详解

  1. 泛型实现打印输出不同的数据类型 (用时11ms)(一个小技巧<计算程序运行时间方法>)
        public static void Main(string[] args)
        {
           Stopwatch stopwatch = new Stopwatch();// 这方法可以获取程序运行时间,便于监控程序性能
           stopwatch.Start();
           PrintPara(12);
           PrintPara("123");
           PrintPara(DateTime.Now);
           stopwatch.Stop();
           Console.WriteLine(stopwatch.ElapsedMilliseconds);
           Console.ReadLine();
        }
        private static void PrintPara<T>(T para)
        {
           Console.WriteLine($"这个参数的数据类型{para.GetType().Name},值为{para}");
        }     
    **评价:只用一个方法实现,而且效率比方法一还要高,优选
    在这个方法里面介绍了泛型集合的使用方法**
2.3 泛型约束

  1. default 关键字:如果要给 T 设置初始值,不能直接设置,则使用default,用法如下
    public class GenericClassdefault<T1, T2>
    {
        //T1 obj = null; // 这种写法是错误的,这里设置默认值时,不能直接赋值,可以使用default
        T1 obj2 = default(T1);// 这种写法,会根据T的具体类型进行默认值的初始化
        //如果是引用类型则是Null,int 类型的则0,String 类型则为""
    }
  1. where 关键字:对调用端传入参数的限制,如下例子
   public class GenericYueShu<T1, T2, T3,T4>
        where T1 : struct //参数类型为值类型
        where T2 : class  //参数类型为引用类型
        where T3 : new()  //参数类型必须有一个无参数的构造方法
        where T4 : ISports // 接口约束
        where T5 :People //基类约束,保证传入值是非密封基类或者基类的子类
    {

    }
2.4 逆变与协变
  1. 什么是协变

父类 a = new 子类();正确
List<父类> a = new List<子类>();错误,原因为,两者间不存在父子关系
可以进行转化,方法为:
List<父类> a = new List<子类>().Select(c=>(子类)c).ToList();
???

2.5 泛型缓存
  1. 以泛型类为例,在调用时候,系统会对一个不同类型的调用,产生新的副本,如下代码:
//如下为泛型类
 public class CacheClass<T>
    {
        static CacheClass()
        {
            if (_typeName == null)
            {
                _typeName = string.Format($"{"类型为:" + typeof(T) + "当前时间为:" + DateTime.Now.ToString("yyyyMMddHHmmssfff")}");
            }
        }
        private static string _typeName;

        public string ReturnTypeName()
        {
            return _typeName;
        }

    }
//如下为泛型类的调用:
string str_Return;
CacheClass<int> a = new CacheClass<int>();
str_Return=a.ReturnTypeName();
Console.WriteLine(str_Return);
Thread.Sleep(300);

CacheClass<string> b = new CacheClass<string>();
str_Return=b.ReturnTypeName();
Console.WriteLine(str_Return);
Thread.Sleep(300);

CacheClass<DateTime> c = new CacheClass<DateTime>();
str_Return=c.ReturnTypeName();
Console.WriteLine(str_Return);
Thread.Sleep(300);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烂笔头技术栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值