c#解读泛型协变和逆变

1.泛型的引入、泛型的声明

//测试obj和指定对象的性能对比
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    for (int i = 0; i < 100_000_000; i++)
    {
        ShowInt(iValue);
    }
    watch.Stop();
    commonSecond = watch.ElapsedMilliseconds;
}
{
    Stopwatch watch = new Stopwatch();
    watch.Start();
    for (int i = 0; i < 100_000_000; i++)
    {
        ShowObject(iValue);
    }
    watch.Stop();
    objectSecond = watch.ElapsedMilliseconds;
}

atch.ElapsedMilliseconds;
}

/// <summary>
/// 基类约束:
///    泛型的类型参数,必须是People或者是People的子类
///    否则无法传入;
///    就可以把这个类型参数当做People来使用;
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="tParameter"></param>
public static void ShowGeneric<T>(T tParameter) where T : People
{
    //Console.WriteLine($"This is {typeof(CommonMethod).Name},parameter={tParameter.GetType().Name},type={tParameter}");
    Console.WriteLine($"People.Id={tParameter.Id}");
    Console.WriteLine($"People.Name={tParameter.Name}"); //访问不了
}

 ///接口约束
 ///类型参数:必须实现这个接口,才能够传入进来;
 ///就可以把参数当成这个接口使用
 public static void ShowGeneric<T>(T tParameter) where T : IWork
 {
     tParameter.Work();
 }
    ///无参数构造函数约束 
    ///传入的参数,必须包含一个无参数构造函数
    ///就可以直接new T     执行无参数构造函数~
    public static void ShowGeneric<T>(T tParameter) where T : new()
    {
        T tt = new T();
    }
    ///值类型约束
    ///必须要传入结构类型,否则无法传入的 
    public static void ShowGeneric<T>(T tParameter) where T : struct
    {

    }


    ///引用类型约束
    ///必须要传入引用类型,否则无法传入的 
    public static void ShowGeneric<T>(T tParameter) where T : class
    {

    }
 ///枚举约束
 ///要求传入的参数必须是一个枚举
 public static void ShowGeneric<T>(T tParameter) where T : Enum
 { 
 }


 public static void ShowGenericNew<T,S,Y,Richard>(T tParameter) where T : struct
 {
 }

 public static void ShowGenericNew2<T, S>(T tParameter) where T : class where S : struct
 {
 }
    public enum ColorType
    {
        Red,
        Green,
        Blue
    }

2.泛型的核心特点+原理,设计思想

      有了约束---传入参数有了局部限制;
        可以享有一些额外的权利~~

3.泛型方法,泛型类,泛型接口,泛型委托

4.泛型约束,泛型缓存,协变,逆变

泛型缓存

/// <summary>
/// 泛型缓存~
/// </summary>
public class GenericCacheTest
{
    public static void Show()
    {

        //普通缓存
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine(DictionaryCache.GetCache<int>()); //GenericCacheInt
                Thread.Sleep(10);
                Console.WriteLine(DictionaryCache.GetCache<long>());// GenericCachelong
                Thread.Sleep(10);
                Console.WriteLine(DictionaryCache.GetCache<DateTime>());
                Thread.Sleep(10);
                Console.WriteLine(DictionaryCache.GetCache<string>());
                Thread.Sleep(10);
                Console.WriteLine(DictionaryCache.GetCache<GenericCacheTest>());
                Thread.Sleep(10);
            }
        }

        //泛型缓存--可以根据不同的类型生成一个新的类的副本;生合二老无数的副本;
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine(GenericCache<int>.GetCache()); //GenericCacheInt
                Thread.Sleep(10);
                Console.WriteLine(GenericCache<long>.GetCache());// GenericCachelong
                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
{ 
    /// <summary>
    /// 静态字典---常驻内存~ 只要程序进程不停止,就会一直保存数据在内存;
    /// </summary>
    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(T); //获取类的type 类型
        if (!_TypeTimeDictionary.ContainsKey(type))
        {
            //写死的,生成数据;  使用当前这个type 作为key 保存到字典中去
            _TypeTimeDictionary[type] = $"{typeof(T).FullName}_{DateTime.Now.ToString("yyyyMMddHHmmss.fff")}";
        }
        return _TypeTimeDictionary[type];
    }
}


/// <summary>
///泛型缓存:
///本质就是泛型类---泛型缓存的应用--手写ORM----有应用~~
/// </summary>
/// <typeparam name="T"></typeparam>
public class GenericCache<T>
{
    /// <summary>
    ///同一个类的静态构造函数在整个进程中,执行且只执行一次;
    /// </summary>
    static GenericCache()
    {
        Console.WriteLine("This is GenericCache 静态构造函数");
        //_TypeTime = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff")); 
        _TypeTime = $"{typeof(T).FullName}_{DateTime.Now.ToString("yyyyMMddHHmmss.fff")}";
    }

    /// <summary>
    /// 只缓存一个字符串
    /// </summary>
    private static string _TypeTime = "";

    public static string GetCache()
    {
        return _TypeTime;
    }

}
协变,逆变

//IEnumerable 也经常把他当成一个集合来用
//协变  就可以让右边用子类,能让左边用父类
//out:修饰类型参数;就可以让右边用子类,能让左边用父类
 

      IEnumerable<Animal> animalList1 = new List<Animal>();
     IEnumerable<Animal> animalList2 = new List<Cat>();
     Func<Animal> func = new Func<Cat>(() => null);

  //协变: Out 类型参数只能做返回值 ,不能做参数 
 

  //协变: Out 类型参数只能做返回值 ,不能做参数 
  ICustomerListOut<Animal> customerList1 = new CustomerListOut<Animal>();
  ICustomerListOut<Animal> customerList2 = new CustomerListOut<Cat>();  //协变 
    /// <summary>
    /// 动物
    /// </summary>
    public class Animal
    {
        public int Id { get; set; }
    }

    /// <summary>
    /// Cat 猫
    /// </summary>
    public class Cat : Animal
    {
        public string Name { get; set; }
    }

    /// <summary>
    /// T 就只能做参数  不能做返回值
    /// </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 协变 只能是返回结果 ,还是int 也是一种高级约束,避免出现问题
    /// 泛型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)  //t 是Cat的时候,这会儿你给我传递了一个Animal进来,子类做参数,但是传递了一个父类简历
        {

        }
    }

    public interface IMyList<in inT, out outT>
    {
        void Show(inT t);
        outT Get();
        outT Do(inT t);
    }

    /// <summary>
    /// out 协变 只能是返回结果 
    /// in  逆变 只能是参数 
    /// </summary>
    /// <typeparam name="T1"></typeparam>
    /// <typeparam name="T2"></typeparam>

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值