zoukankan      html  css  js  c++  java
  • C# 泛型(二)

    通过前一篇(https://www.cnblogs.com/Dewumu/p/10498831.html)我们大概了解到了泛型的使用,那么泛型还有哪些使用呢?

    五、泛型之协变、裂变

    “协变”是指能够使用与原始指定的派生类型相比,派生程度更大的类型。 

    “逆变”则是指能够使用比原始指定的类型更泛型(派生程度更小)的类型。 

    所谓协变逆变,都是跟泛型相关,
    只能放在接口或者委托的泛型参数前面
    out 协变covariant 修饰返回值
    in 逆变contravariant 修饰传入参数

    这里有两个类型,抽象父类(动物类)子类(猫)

        public abstract class Animal
        {
    
        }
        public class Cat:Animal
        {
    
        }
    示例

    根据里氏转换,我们知道子类可以赋值给父类,但是为什么List<Animal> animals=new List<Cat>();无法编译通过呢?这是因为C#是强类型语言,List<Cat>并不继承 List<Animal>因此List<Cat>需要把集合中的实体转为Animal才能使等式成立;

               {
                    Cat cat = new Cat();
                    Animal animal = new Cat();
                }
                {
                    List<Cat> cats = new List<Cat>();
                    //List<Animal> animals=new List<Cat>();
                    List<Animal> animals = new List<Cat>().Select(a => (Animal)a).ToList();
                }
    View Code

    协变的出现很好的解决了这种情况

    using System.Runtime.CompilerServices;
    
    namespace System.Collections.Generic
    {
        //
        // 摘要:
        //     公开枚举数,该枚举数支持在指定类型的集合上进行简单迭代。
        //
        // 类型参数:
        //   T:
        //     要枚举的对象的类型。此类型参数是协变。即可以使用指定的类型或派生程度更高的类型。有关协变和逆变的更多信息,请参见泛型中的协变和逆变。
        [TypeDependencyAttribute("System.SZArrayHelper")]
        public interface IEnumerable<out T> : IEnumerable
        {
            //
            // 摘要:
            //     返回一个循环访问集合的枚举器。
            //
            // 返回结果:
            //     可用于循环访问集合的 System.Collections.Generic.IEnumerator`1。
            IEnumerator<T> GetEnumerator();
        }
    }
    View Code
               {
                    IEnumerable<Cat> cats = new List<Cat>();
                    IEnumerable<Animal> animals = new List<Animal>();
                }
                {
                    IEnumerable<Animal> animals = new List<Cat>();
                }
    View Code

    学完了,协变,在看看逆变

       public interface ICustomerList<in InT>
        {
            void Show(InT inT);
        }
        public class CustomerList<InT> : ICustomerList<InT>
        {
            public void Show(InT inT)
            {
                return;
            }
        }
    View Code

    动物会叫,猫一定也会叫

               {
                    ICustomerList<Cat> cats = new CustomerList<Cat>();
                    ICustomerList<Animal> animals = new CustomerList<Animal>();
                }
                {
                    ICustomerList<Cat> animals = new CustomerList<Animal>();
                    animals.Show(new Cat());
                }
    View Code

    协变(covariant )out 只能是返回值     逆变(contravariant )in只能是参数

        public interface IMyList<in inT, out outT>
        {
            void Show(inT _int);
            outT Get();
            outT Post(inT _int);
    
            //out 只能是返回值   in只能是参数
            //void Show(outT _outt);
            //inT Get();
        }
        public class MyList<InT, OutT> : IMyList<InT, OutT>
        {
            public OutT Get()
            {
                return default(OutT);
            }
    
            public OutT Post(InT _int)
            {
                return default(OutT);
            }
            public void Show(InT _int)
            {
                return;
            }
        }
    View Code
               {
                    IMyList<Cat, Animal> list1 = new MyList<Cat, Animal>();
                    IMyList<Cat, Animal> list2 = new MyList<Cat, Cat>();//协变
                    IMyList<Cat, Animal> list3 = new MyList<Animal, Animal>();//逆变
                    IMyList<Cat, Animal> list4 = new MyList<Animal, Cat>();//协变+逆变
                }
    View Code

    六、泛型缓存

    我们知道静态字段存放在特定的静态区域,读写都很快,而泛型缓存正是运用的这种特性

        /// <summary>
        /// 每个不同的T,都会生成一份不同的副本
        /// 适合不同类型,需要缓存一份数据的场景,效率高
        /// </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;
            }
            //common<int>(1)
        }
    View Code

    泛型类,会为每个不同类型生成一份副本,效率很高

    在Main()函数中调用

                    for (int i = 0; i < 5; i++)
                    {
                        Console.WriteLine(GenericCache<int>.GetCache());
                        Console.WriteLine(GenericCache<long>.GetCache());
                        Console.WriteLine(GenericCache<DateTime>.GetCache());
                        Console.WriteLine(GenericCache<string>.GetCache());
                    }
    View Code

    执行结果如下:

    静态构造函数被执行了4次,这是因为有4种类型

    而循环5次,每次相同类型得到的结果是一样的,不同类型的结果是不同的,这就是充分利用了泛型和静态字段的特点达到的效果。

    但是这种缓存方式也是有弊端的,清理、释放不方便,所以请勿滥用!!!

    本文参考文档:https://www.cnblogs.com/loverwangshan/p/9871548.html;

    https://www.cnblogs.com/qixuejia/p/4383068.html;

    https://www.cnblogs.com/CLR010/p/3274310.html;

    微软文档地址:https://docs.microsoft.com/zh-cn/dotnet/standard/generics/covariance-and-contravariance;

    https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/covariance-contravariance/;

    https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/covariance-contravariance/variance-in-generic-interfaces;

  • 相关阅读:
    element ui 表单清空
    element ui 覆盖样式 方法
    element ui 修改表单值 提交无效
    element ui 抽屉里的表单输入框无法修改值
    element ui 抽屉首次显示 闪烁
    css 左侧高度 跟随右侧内容高度 自适应
    PICNUF框架
    elementui 抽屉组件标题 出现黑色边框
    vue 子组件跨多层调用父组件中方法
    vue 编辑table 数据 未点击提交,table里的数据就发生了改变(深拷贝处理)
  • 原文地址:https://www.cnblogs.com/Dewumu/p/10503288.html
Copyright © 2011-2022 走看看