.NET/C# 高级开发(一) 泛型

泛型入门:泛型方法,泛型类,泛型接口,泛型委托

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace 泛型
{
    
    class Program
    {
        static void Main(string[] args)
        {

        }
        //泛型方法:参数作为泛型的方法
        //服务于不同类型的共同需求的方法
        public void 泛型方法_a<T>(T t)
        {

        }
        //泛型方法:参数作为泛型的方法
        //多泛型参数的方法,不可以用关键字
        //不建议使用类名,变量名,方法名
        public void 泛型方法_b<T,B,C>(T t)
        {

        }
        //泛型方法:返回值作为泛型的方法
        //object可以强转成泛型
        public T 泛型方法_c<T>(object t)
        {
            return (T)t;
        }
        //泛型方法:返回值作为泛型的方法
        //T t = default(T);//空的泛型变量,不可以用null
        public T 泛型方法_d<T>()
        {
            T t = default(T);
            return t;
        }
    }
    //泛型类:将服务于不同类型的共同需求集合起来
    public class 泛型类<T>
    {

    }
    //泛型接口:服务于不同类型的共同需求的接口
    public interface 泛型接口<T>
    {

    }
    //泛型委托:服务于不同类型的共同需求的委托
    public delegate void 泛型委托<T>();
}

泛型使用:延迟声明

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 泛型
{
    
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("************************声明不同类型变量方便演示**************************");
            int iValue = 123;
            string sValue = "456";
            DateTime dValue = DateTime.Now;
            object oValue = "789";

            Console.WriteLine("************************ShowObject**************************");
            //利用Object的基类特性传入参数,
            //会产生两个问题:
            //1.装箱拆箱,性能损耗
            //  传入一个INT值(栈)
            //  (装箱) object是在堆里面的引用类型,如果把INT传递进来,会把值从栈里面Copy到堆里面
            //  (拆箱) 使用的时候需要用到对象值,又会从堆把值Copy到栈
            //2.类型安全
            //  传入的对象没有限制
            //  如果传入的类型超出它的使用类型就会出问题
            ShowObject(iValue);
            ShowObject(sValue);
            ShowObject(dValue);
            ShowObject(oValue);
            Console.WriteLine("************************ShowT**************************");
            //泛型方法使用时要指明参数类型,
            //编译器根据传入的参数类型自动推算泛型类型,这被我们成为语法糖,语法糖是编译器提供的便捷功能的代称
            //如果指明的类型参数和传入的参数类型不符,编译不会通过
            //编译阶段用占位符代替,是在运行阶段才确定的类型
            //这类做法使用了延迟声明的设计思想,推迟一切可以推迟的
            ShowT<int>(iValue);
            ShowT(sValue);
            ShowT(dValue);
            ShowT(oValue);
            Console.ReadKey();
        }
        static void ShowObject(object oParameter)//普通方法
        {
            Console.WriteLine($"传入的参数类型{oParameter.GetType().FullName},类型的值={tParameter}");
        }
        /// <summary>
        /// 泛型方法:方法名称后面加上尖括号,里面是一个可以代指任何类型的代号
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tParameter"></param>
        static void ShowT<T>(T tParameter)
        {
            Console.WriteLine($"传入的参数类型={tParameter.GetType().FullName},类型的值={tParameter}");
        }
    }
}

泛型扩展:泛型约束

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace 泛型
{

    class Program
    {
        static void Main(string[] args)
        {
            people peo = new people()
            {
                Id = 123,
                Name = "人",
            };
            Chinese chi = new Chinese()
            {
                Id = 234,
                Name = "中国人",
            };
            Hubei hub = new Hubei()
            {
                Id = 345,
                Name = "湖北人",
            };
            Japanese Jap = new Japanese()
            {
                Id = 456,
                Name = "日本人",
            };
            Show(peo);
            Show(chi);
            Show(hub);
            Show(Jap);
            Console.ReadKey();
        }
        public static void Show<T>(T t)
            //where T : new     //无参数构造函数,没有带参数构造函数
            //where T : struct    //值类型约束,当返回类型为泛型时可以用关键字default(T);会根据T的类型获得一个默认的值
            //where T : class    //引用类型约束

            //where T : ISports    //接口约束
            //where T : people     //基类约束
            where T : people, ISports0, ISports1, new()  //可以被一个基类/父类,多个接口同时约束,
            //约束可以叠加但是有些不可以一起使用,因为没有意义
        {
            Console.WriteLine($"This is {typeof(Program)},t={t.GetType().Name},type={t}");
            Console.WriteLine($"{t.Id}  {t.Name}");
            //return default(T);
        }
        public static void Show<T,S>(T t)
            where T : people, ISports0, ISports1, new()
            where S : new ()   //多个泛型可以直接约束
            //where T : people, ISports0, ISports1, new()
            //where S : T
            //如果两个泛型约束相同可以这样写
        {
            Console.WriteLine($"This is {typeof(Program)},t={t.GetType().Name},type={t}");
            Console.WriteLine($"{t.Id}  {t.Name}");
            //return default(T);
        }
    }
    public class ShowClass_0<T> where T : ISports0
    {
        //泛型类约束
    }
    public class ShowClass_1<T,S> where T : ISports0 where S:ISports1
    {
        //多泛型参数的泛型类约束
    }
    public class people_0<T, S> : ShowClass_0<T>, ISports2<S>
        where T:ISports0
        where S:class
    {
        //使用了带有约束的父类或接口时,如果没有指明泛型类型,需要指明同父类或接口相同的约束
    }
    public class people_1<T, S> : ShowClass_0<Japanese>, ISports2<string>
    {
        //使用了带有约束的父类或接口时,如果指明了泛型类型,需要指明同父类或接口相同约束的类型
    }


    public interface ISports0
    {
        
    }
    public interface ISports1
    {

    }
    public interface ISports2<S>
        where S : class
    {

    }
    public class people: ISports0,ISports1
    {
        public int Id;
        public string Name;
    }
    public class Chinese : people { }
    public class Hubei : people { }
    public class Japanese : people { }
}

泛型扩展:泛型缓存

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace 泛型
{
    
    class Program
    {
        static void Main(string[] args)
        {
            //每个不同的T都会生成一份不同的副本
            //适合不同类型都需要缓存一份自身数据的场景,效率高
            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<Program>.GetCache());
                Thread.Sleep(10);
            }
        }
    }
    //字典缓存,静态属性常驻内存,把传入类型作为键
    //示例
    public class DictionaryCache
    {
        private static Dictionary<Type, string> _TypeTimeDictionary = null;
        static DictionaryCache()
        {
            Console.WriteLine("静态构造函数,全局只执行一次");
            _TypeTimeDictionary = new Dictionary<Type, string>();//创建静态字典
        }
        public static string GetCache<T>()
        {
            Type type = typeof(T);
            if (!_TypeTimeDictionary.ContainsKey(type))//是否不包含当前键
            {
                _TypeTimeDictionary[type] = string.Format("{0}_{1}",typeof(T).FullName,DateTime.Now.ToString("yyyyMMddHHmmss.fff"));
            }
            return _TypeTimeDictionary[type];
        }
    }
    //静态缓存,把传入类型作为键
    //示例
    public class GenericCache<T>
    {
        private static string _TypeTime = "";
        static GenericCache()
        {
            Console.WriteLine("静态构造函数,全局只执行一次");
            _TypeTime = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff"));
        }
        public static string GetCache()
        {
            return _TypeTime;
        }
    }
    
}

泛型扩展:协变逆变

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;


namespace 泛型
{

    class Program
    {
        static void Main(string[] args)
        {
            //-------------------------------------------------------------------------------------------
            //Bird bir_ = new Sparrow();//麻雀一定是一只鸟
            //Sparrow spa = new Bird();//鸟不一定是一只麻雀,也有可能是其他鸟
            //-------------------------------------------------------------------------------------------
            //List<Bird> bir = new List<Bird>();
            //List<Bird> bir1 = new List<Sparrow>();
            //List集合不可以用子类实例化父类,因为编译器会编译成完全不同的两个类,也不存在父子关系
            //-------------------------------------------------------------------------------------------
            ///协变
            {
                //-------------------------------------------------------------------------------------------
                //协变:
                //      可以让我们用子类实例化父类
                //      协变的泛型参数只能作为返回结果,不能作为参数
                //个人理解:
                //      子类不包含父类,故子类实例父类不够完整
                //      如果作为参数以父类的方式操作子类会造成不可预料的后果
                //      因为操作的类型也可能是父类自身类型
                //      所以只能作为返回结果
                OutList<Bird> bir_0 = new OutList_<Bird>();
                bir_0.Get();
                OutList<Bird> bir_1 = new OutList_<Sparrow>();
                bir_1.Get();
                //      在协变中父类不可以实例化子类
                //OutList<Sparrow> bir_2 = new OutList_<Bird>();
                //-------------------------------------------------------------------------------------------
            }
            ///逆变
            {
                //-------------------------------------------------------------------------------------------
                //逆变:
                //      可以让我们用父类实例化子类
                //      逆变的泛型参数只能作为参数,不能作为返回结果
                //个人理解:
                //      父类包含子类,故父类拥有子类的完全属性
                //      如果作为返回类型的话编译器识别不出当前泛型的具体类型
                //      所以只能作为参数传递
                InList<Sparrow> spa_0 = new InList_<Sparrow>();
                spa_0.Show(new Sparrow());
                InList<Sparrow> spa_1 = new InList_<Bird>();
                spa_1.Show(new Sparrow());
                //      在逆变中子类不可以实例化父类
                //InList<Bird> spa_2 = new InList_<Sparrow>();
                //-------------------------------------------------------------------------------------------
            }
            ///协变+逆变
            {
                //-------------------------------------------------------------------------------------------
                InOutList<Sparrow, Bird> ino_0 = new InOutList_<Sparrow, Bird>();
                //协变,第二个泛型参数定义了out,所以可以子类实例化父类
                InOutList<Sparrow, Bird> ino_1 = new InOutList_<Sparrow, Sparrow>();
                //逆变,第一个泛型参数定义了in,所以可以父类实例化子类
                InOutList<Sparrow, Bird> ino_2 = new InOutList_<Bird, Bird>();
                //协变+逆变
                InOutList<Sparrow, Bird> ino_3 = new InOutList_<Bird, Sparrow>();
                //-------------------------------------------------------------------------------------------
            }
        }
    }
    public interface InOutList<in Tin,out Tout>
    {

        void Show(Tin tin);
        Tout Get();
        Tout Do(Tin tin);
    }
    public class InOutList_<Tin, Tout> : InOutList<Tin, Tout>
    {
        public Tout Do(Tin tin)
        {
            return default(Tout);
        }

        public Tout Get()
        {
            return default(Tout);
        }

        public void Show(Tin tin)
        {
        }
    }
    public  interface OutList<out T>
    {
        //泛型参数带有out的称为协变,out只有在泛型和委托中才有协变的概念
        T Get();
    }
    public class OutList_<T> : OutList<T>
    {
        //泛型接口的实现,注意泛型参数不能写错和漏写
        public T Get()
        {
            //根据传递的参数返回默认值
            return default(T);
        }
    }
    public  interface InList<in T>
    {
        //泛型参数带有in的称为逆变,in只有在泛型和委托中才有逆变的概念
        void Show(T t);
    }
    public class InList_<T> : InList<T>
    {
        //泛型接口的实现,注意泛型参数不能写错和漏写
        public void Show(T t)
        {
            //不做任何操作,只是为了演示
        }
    }
    public class Bird
    {
        public int id { get; set; }
    }
    public class Sparrow : Bird
    {
        public string Name { get; set; }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值