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;

  • 相关阅读:
    关于苹果IPhone/Ipad(IOS)开发者证书申请及安装、真机调试、发布的参考文章
    vs 关闭警告
    真机测试及布署Code Sign error问题总结
    在 Win32 Application 和 Win32 Console Application 中使用 MFC
    获取应用程序路径的区别
    js日期控件
    SQL SERVER 企业管理器 MMC 无法创建管理单元
    进程查看两利器
    用PowerDesigner逆向数据库工程时”Unable to list the table"错误的解决方法
    SQL 附加无日志数据库
  • 原文地址:https://www.cnblogs.com/Dewumu/p/10503288.html
Copyright © 2011-2022 走看看