• 【学习笔记】泛型


    1、泛型类、泛型方法、泛型接口、泛型委托。

    2、用到的设计思想:延迟声明(能推迟做的事情就尽量推迟做)。

    3、语法糖:编译器自动帮我们识别类型,泛型不是简单的语法糖,它是框架升级和语法糖的双重结果。

    4、泛型就是用一个东西来满足多种不同类型的需求的。

    5、引入泛型前使用object作为类型参数有2个问题

      1)、装箱拆箱,性能损耗。传入一个int值(栈) ,object又在堆里面,如果把int传递进来,就会把值从栈里面copy到堆里(装箱)。使用的时候,又需要用对象值,又会copy到栈(拆箱)。

      2)、类型安全问题,可能会有,因为传递的对象是没有限制的。

    6、泛型约束

    /*
    * 五种约束:
    * 
    * where T:struct  值类型约束:类型参数必须为值类型
    * 
    * where T:class   引用类型约束:适用于类、接口、委托、数组等,类型参数必须为引用类型
    * 
    * where T:new()   new()无参构造器约束:类型参数必须有一个公有的无参构造器
    * 
    * where T:<base class name>   基类约束:类型参数必须是指定的基类或是派生自指定的基类
    * 
    * where T:<interface>   接口约束:类型参数必须是指定接口或实现指定的接口,可以指定多个接口约束,约束接口也可以是泛型的
    * 
    * 
    * 组合约束:用的不多
    * 在约束列表中,第一个必须是引用类型约束或者值类型约束,或者是基类约束,然后才是接口约束,最后才是new()约束
    * 指定引用类型约束或值类型约束的同时也指定基类约束是非法的
    * 
    * 同一个类型形参可以使用多个约束,中间用逗号隔开,例如:
    * class Test<T> where T : Myclass, Interface, new(){......}
    * 替换T的类型实参必须是继承Myclass类,且实现Interface接口,且拥有一个无参构造器
    * 
    * 在使用两个或多个类型形参时,也可以使用多条where子句分别为它们指定约束
    */

     下面通过一个简单的例子来看下如何使用

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace ConsoleApp1
    {
        /// <summary>
        /// 泛型类
        /// </summary>
        public class MyGeneric<T1, T2>
            where T1 : Person, ISay //T1必须是Person类或者是Person的派生类,并且实现了ISay接口
            where T2 : ISky //T2必须是实现了ISky接口
        {
            public void Say(T1 t)
            {
                t.Say(t.Name);
            }
    
            public void Sky(T2 t)
            {
                t.Sky();
            }
    
            /// <summary>
            /// 泛型方法
            /// </summary>
            /// <typeparam name="T3"></typeparam>
            /// <param name="t"></param>
            /// <returns></returns>
            public T3 GetDefault<T3>(T3 t)
                where T3 : struct
            {
                return default(T3);
            }
        }
    
        /// <summary>
        /// 人类
        /// </summary>
        public class Person
        {
            /// <summary>
            /// 姓名
            /// </summary>
            public string Name { get; set; }
        }
    
        /// <summary>
        /// 说接口
        /// </summary>
        public interface ISay
        {
            void Say(string name);
        }
    
        /// <summary>
        /// 飞接口
        /// </summary>
        public interface ISky
        {
            void Sky();
        }
    }

    7、协变和逆变

      1)、二者只使用与泛型委托和泛型接口。

      2)、协变:由子类方向 向 父类方向 转变,用out关键字,T类型只能用于返回值。

      3)、逆变:由父类方向 向 子类方向 转变,用in关键字,T类型只能用于传入参数。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace MyGeneric.Extend
    {
        /// <summary>
        /// 所谓协变逆变,都是跟泛型相关,
        /// 只能放在接口或者委托的泛型参数前面
        /// out 协变covariant    修饰返回值 
        /// in  逆变contravariant  修饰传入参数
        /// </summary>
        public class CCTest
        {
            public static void Show()
            {
                //Func<int, string>
                {
                    Bird bird1 = new Bird();
                    Bird bird2 = new Sparrow();//子类实例化 麻雀当然是个bird
                    Sparrow sparrow1 = new Sparrow();
                    //Sparrow sparrow2 = new Bird();//子类变量  不能用父类实例化
                }
    
                {
                    List<Bird> birdList1 = new List<Bird>();
                    //List<Bird> birdList2 = new List<Sparrow>();
                    //一堆麻雀  难道不是  一堆鸟吗?  语义上是可以的
                    //不成立,语法不通过,原因是List<Bird>是一个类--List<Sparrow>也是一个类,没有父子关系
    
                    List<Bird> birdList3 = new List<Sparrow>().Select(c => (Bird)c).ToList();
                }
    
                //泛型还有不够和谐的地方---泛型不就是为了书写方便
                {
                    //协变:就是让右边可以用子类,让泛型用起来更方便
                    //out修饰,协变后,T只能作为返回值,不能当参数
                    IEnumerable<Bird> birdList1 = new List<Bird>();
                    IEnumerable<Bird> birdList2 = new List<Sparrow>();
    
                    Func<Bird> func = new Func<Sparrow>(() => null);
    
                    ICustomerListOut<Bird> customerList1 = new CustomerListOut<Bird>();
                    ICustomerListOut<Bird> customerList2 = new CustomerListOut<Sparrow>();
                    customerList2.Get();
                }
    
                {
                    //逆变:就是让右边可以用父类,让泛型用起来更方便
                    //in修饰,逆变后,T只能作为当参数  不能做返回值,
                    ICustomerListIn<Sparrow> customerList2 = new CustomerListIn<Sparrow>();
                    ICustomerListIn<Sparrow> customerList1 = new CustomerListIn<Bird>();
                    customerList1.Show(new Sparrow());
    
                    ICustomerListIn<Bird> birdList1 = new CustomerListIn<Bird>();
                    birdList1.Show(new Sparrow());
                    birdList1.Show(new Bird());
    
                    Action<Sparrow> act = new Action<Bird>((Bird i) => { });
                }
    
                {
                    IMyList<Sparrow, Bird> myList1 = new MyList<Sparrow, Bird>();
                    IMyList<Sparrow, Bird> myList2 = new MyList<Sparrow, Sparrow>();//协变
                    IMyList<Sparrow, Bird> myList3 = new MyList<Bird, Bird>();//逆变
                    IMyList<Sparrow, Bird> myList4 = new MyList<Bird, Sparrow>();//协变+逆变
                }
            }
        }
    
        /// <summary>
        ////// </summary>
        public class Bird
        {
            public int Id { get; set; }
        }
    
        /// <summary>
        /// 麻雀
        /// </summary>
        public class Sparrow : Bird
        {
            public string Name { get; set; }
        }
    
        /// <summary>
        /// 逆变
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public interface ICustomerListIn<in T>
        {
            //T Get();//不能做返回值
    
            void Show(T t);
        }
    
        public class CustomerListIn<T> : ICustomerListIn<T>
        {
            //public T Get()
            //{
            //    return default(T);
            //}
    
            public void Show(T t)
            {
            }
        }
    
        /// <summary>
        /// out 协变 只能是返回结果,不能做参数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public interface ICustomerListOut<out T>
        {
            T Get();
    
            //void Show(T t);
        }
    
        public class CustomerListOut<T> : ICustomerListOut<T>
        {
            public T Get()
            {
                return default(T);
            }
    
            //public void Show(T t)
            //{
    
            //}
        }
    
        public interface IMyList<in inT, out outT>
        {
            void Show(inT t);
    
            outT Get();
    
            outT Do(inT t);
    
            ////out 只能是返回值   in只能是参数
            //void Show1(outT t);
            //inT Get1();
        }
    
        public class MyList<T1, T2> : IMyList<T1, T2>
        {
            public void Show(T1 t)
            {
                Console.WriteLine(t.GetType().Name);
            }
    
            public T2 Get()
            {
                Console.WriteLine(typeof(T2).Name);
                return default(T2);
            }
    
            public T2 Do(T1 t)
            {
                Console.WriteLine(t.GetType().Name);
                Console.WriteLine(typeof(T2).Name);
                return default(T2);
            }
        }
    }
  • 相关阅读:
    DataReader对象
    程序员感悟——路该怎么走
    采访:服务器系统企业选择了谁? java程序员
    Android 设置Activity大小不再全屏原理 java程序员
    学习软件开发千万不要犯的错误 java程序员
    XML布局技巧 java程序员
    Android 书籍 java程序员
    使用jQuery开发一个响应式超酷整合RSS信息阅读杂志 java程序员
    软件开发工程师的20条编程经验 java程序员
    jsp中文乱码完美解决方案(原创) java程序员
  • 原文地址:https://www.cnblogs.com/xyh9039/p/12549366.html
Copyright © 2020-2023  润新知