(精华)2020年8月8日 C#基础知识点 泛型

原理图
在这里插入图片描述

class Program
    {
        static void Main(string[] args)
        {
            try
            {
                int iValue = 123;
                string sValue = "456";
                DateTime dtValue = DateTime.Now;
                object oValue = "789";
                Console.WriteLine("***********************普通方法重载***********************");
                CommonMethod.ShowInt(iValue);
                CommonMethod.ShowString(sValue);
                CommonMethod.ShowDateTime(dtValue);
                Console.WriteLine("***********************Object对象接受(拆装箱)***********************");
                CommonMethod.ShowObject(oValue);
                CommonMethod.ShowObject(iValue);
                CommonMethod.ShowObject(sValue);
                CommonMethod.ShowObject(dtValue);
                Console.WriteLine("***********************泛型***********************");
                // 泛型只有:泛型方法、泛型类、泛型接口、泛型委托 
                //泛型方法调用的时候,需要加上<>,而且需要指定具体的类型、指定的类型和传入的参数类型保持一致。
                CommonMethod.Show(iValue); //如果类型参数,可以通过参数类型推导出来,那么就可以省略
                                           /* CommonMethod.Show<int>(sValue);*/// 因为类型错了 
                CommonMethod.Show(sValue);
                CommonMethod.Show<DateTime>(dtValue);
                CommonMethod.Show<object>(oValue);
                Console.WriteLine("***********************泛型缓存***********************");
                GenericCacheTest.Show();
                Console.WriteLine("***********************泛型约束***********************");
                //无约束情况 
                People people = new People()
                {
                    Id = 123,
                    Name = "人民"
                };

                Chinese chinese = new Chinese()
                {
                    Id = 234,
                    Name = "中国"
                };
                Hubei hubei = new Hubei()
                {
                    Id = 345,
                    Name = "湖北"
                };
                Japanese japanese = new Japanese()
                {
                    Id = 678,
                    Name = "日报"
                };

                // Object 方法因为可以出入任何类型,没有限制,如果传入的类型不匹配,就会发生异常(类型安全问题)
                //GenericConstraint.ShowObject(people);
                //GenericConstraint.ShowObject(chinese);
                //GenericConstraint.ShowObject(hubei);
                //GenericConstraint.ShowObject(japanese);

                //GenericConstraint.Show(people);
                //GenericConstraint.Show(chinese);
                //GenericConstraint.Show(hubei);
                //GenericConstraint.Show(japanese);

                //有约束情况
               // GenericConstraint.GenericShow(123);

                GenericConstraint.GenericShow(people);
                GenericConstraint.GenericShow(chinese);
                GenericConstraint.GenericShow(hubei);
                GenericConstraint.GenericShow(japanese);//
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.Read();
        }
    }

对应的类

public class CommonMethod
    {
        /// <summary>
        /// 打印个int值 
        /// </summary>
        /// <param name="iParameter"></param>
        public static void ShowInt(int iParameter)
        {
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod).Name, iParameter.GetType().Name, iParameter);
        }
        /// <summary>
        /// 打印个string值
        /// </summary>
        /// <param name="sParameter"></param>
        public static void ShowString(string sParameter)
        {
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod).Name, sParameter.GetType().Name, sParameter);
        }
        /// <summary>
        /// 打印个DateTime值
        /// </summary>
        /// <param name="oParameter"></param>
        public static void ShowDateTime(DateTime dtParameter)
        {
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod).Name, dtParameter.GetType().Name, dtParameter);
        }
        /// <summary> 
        ///为什么用object 作为参数类型,调用的时候,可以把任何类型都传进来
        ///
        ///C#: 任何父类出现的地方  都可以用子类代替;
        ///Object类型是一切类型的父类
        ///
        ///Object 出现的都可以让任何类型传进来
        /// 
        /// 但是:有2个问题
        ///        性能问题:会出现装箱和拆箱;
        ///        类型安全问题。 
        /// </summary>
        /// <param name="oParameter"></param>
        public static void ShowObject(object oParameter)
        {
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod), oParameter.GetType().Name, oParameter);
        }

        /// <summary>
        /// 泛型方法:需要在方法名的后面带一个<>,需要定义T, T是什么呢? 不知道, 
        /// T:类型参数,只是一个占位符,类型在声明其实不确定,在调用的时候,确定类型。
        ///  
        /// 延迟声明,推迟一切可以推迟的,事情能晚点做就晚点做。 
        /// 在使用的时候,需要指定明确的类型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tParameter"></param>
        public static void Show<T>(T tParameter)
        {
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod), tParameter.GetType().Name, tParameter);
        }
    }
public class GenericCacheTest
    {
        public static void Show()
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine(GenericCache<int>.GetCache());
                Thread.Sleep(10);
                Console.WriteLine(GenericCache<long>.GetCache());
                Thread.Sleep(10);
                Console.WriteLine(GenericCache<DateTime>.GetCache());
                Thread.Sleep(10);
                Console.WriteLine(GenericCache<string>.GetCache());
                Thread.Sleep(10);
                Console.WriteLine(GenericCache<GenericCacheTest>.GetCache());
                Thread.Sleep(10);
            }
        }
    }

    /// <summary>
    /// 字典缓存:静态属性常驻内存
    /// </summary>
    public class DictionaryCache
    {
        private static Dictionary<Type, string> _TypeTimeDictionary = null;
        static DictionaryCache()
        {
            Console.WriteLine("This is DictionaryCache 静态构造函数");
            _TypeTimeDictionary = new Dictionary<Type, string>();
        }
        public static string GetCache<T>()
        {
            Type type = typeof(Type);
            if (!_TypeTimeDictionary.ContainsKey(type))
            {
                _TypeTimeDictionary[type] = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff"));
            }
            return _TypeTimeDictionary[type];
        }
    }


    /// <summary>
    ///泛型缓存: 会根据传入的不同类型,分别生成不同的副本 
    ///
    /// 可以接受任何类型,需要根据不同类型缓存一部分数据就可以使用,效率更好
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class GenericCache<T>
    {
        static GenericCache()
        {
            Console.WriteLine("This is GenericCache 静态构造函数");
            _TypeTime = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff"));
        }

        private static string _TypeTime = "";

        public static string GetCache()
        {
            return _TypeTime;
        }
    }
/// <summary>
    /// 泛型约束 
    /// </summary>
    public class GenericConstraint
    {
        public static void ShowObject(object oParameter)
        {
            //  Console.WriteLine(oParameter.Id);// 编译器就报错,因为C# 是强类型的语言,在编译的时候就要确定类型
            People people = (People)oParameter;
            Console.WriteLine(people.Id);
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod), oParameter.GetType().Name, oParameter);
        }
        public static void Show<T>(T tParameter)
           // where T : People //基类约束,你只能是一个People ,所以这里参数只能传入People或者People子类
           where T : ISports // 接口约束
        {
            //Console.WriteLine(tParameter.Id);  //又报错了 

            //  Console.WriteLine(tParameter.Id);
            // 加了 T : ISports约束以后,发现不能访问Id

            tParameter.Pingpang();

            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod), tParameter.GetType().Name, tParameter);
        }


        public static void GenericShow<T>(T tParameter)
        // where T : class // 引用类型约束  就只能传入引用类型的参数
        // where T : struct
        // where T : new()// 无参数构造偶函数约束
        {
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod), tParameter.GetType().Name, tParameter);
        }


        public static void GenericShow1<T>(T tParameter)
        where T : class, new() // 泛型约束可以结合使用 ,用逗号分隔就OK
        {
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod), tParameter.GetType().Name, tParameter);
        }

        public static T GenericShow2<T>()
        {
            return default(T); // default关键字  
        }              
    }

协变和逆变

/// <summary>
    /// 只能放在接口或者委托的泛型参数前面
    /// out 协变covariant    修饰返回值 
    /// in  逆变contravariant  修饰传入参数
    /// </summary>
    public class CCTest
    {
        public static void Show()
        {
            {
                Bird bird1 = new Bird();
                Bird bird2 = new Sparrow();
                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修改类型参数,协变:可以让右边使用子类

                // 使用协变时候,可以把子类放在右边,这才是泛型该有的样子

                IEnumerable<Bird> birdList1 = new List<Bird>();
                IEnumerable<Bird> birdList2 = new List<Sparrow>(); //为什么可以写?
                 
                ICustomerListOut<Bird> customerList1 = new CustomerListOut<Bird>();
                ICustomerListOut<Bird> customerList2 = new CustomerListOut<Sparrow>();
            }

            {//逆变
                //int修改类型参数,逆变:可以让右边使用父类
                // 类型参数只能作为参数 ,不能作为返回值

                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());

            }

            {
                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>();//协变+逆变
            }

            //完全能理清楚 刷个1  
            //能清楚80%  2   60%  3
        }
    }

    public class Bird
    {
        public int Id { get; set; }
    }
    public class Sparrow : Bird
    {
        public string Name { get; set; }
    }

    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修改  协变  T 就只能做返回值 ,不能做参数
    /// </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);
        }
    }

猜你喜欢

转载自blog.csdn.net/aa2528877987/article/details/107803460