IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> C# 进阶语法 (泛型) -> 正文阅读

[Java知识库]C# 进阶语法 (泛型)

1 引入泛型:延迟声明
2 如何声明和使用泛型
3 泛型的好处和原理
4 泛型类、泛型方法、泛型接口、泛型委托
5 泛型约束
6 协变 逆变(选修)
7 泛型缓存(选修)

List就是泛型,为什么要有泛型?
List是一个集合,可能是一组int 也可能是一组string
泛型就是用一个东西来满足多种不同类型的需求的

1 任何父类出现的地方,都可以用子类来代替
2 object是一切类型的父类

object类型参数有2个问题:
1 装箱拆箱,性能损耗
传入一个int值(栈)
object又在堆里面,如果把int传递进来,就会把值从栈里面copy到堆里
使用的时候,又需要用对象值,又会copy到栈(拆箱)

2 类型安全问题,可能会有,因为传递的对象是没有限制的

Model.cs

namespace MyGeneric
{
    public interface ISports
    {
        void Pingpang();
    }

    public interface IWork
    {
        void Work();
    }


    public class People
    {
        //public People(int i)
        //{

        //}

        public int Id { get; set; }
        public string Name { get; set; }

        public void Hi()
        { }

    }

    public class Chinese : People, ISports, IWork
    {
        public void Tradition()
        {
            Console.WriteLine("仁义礼智信,温良恭俭让");
        }
        public void SayHi()
        {
            Console.WriteLine("吃了么?");
        }

        public void Pingpang()
        {
            Console.WriteLine("打乒乓球...");
        }

        public void Work()
        {
            throw new NotImplementedException();
        }
    }

    public class Hubei : Chinese
    { 
        public string Changjiang { get; set; }
        public void Majiang()
        {
            Console.WriteLine("打麻将啦。。");
        }
    }


    public class Japanese : ISports
    {
        public int Id { get; set; }
        public string Name { get; set; }
         
        public void Pingpang()
        {
            Console.WriteLine("打乒乓球...");
        }
    }
}

Monitor.cs

namespace MyGeneric
{
    /// <summary>
    /// 性能对比
    /// </summary>
    public class Monitor
    {
        public static void Show()
        {
            Console.WriteLine("****************Monitor******************");
            {
                int iValue = 12345;
                long commonSecond = 0;
                long objectSecond = 0;
                long genericSecond = 0;

                {
                    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;
                }
                {
                    Stopwatch watch = new Stopwatch();
                    watch.Start();
                    for (int i = 0; i < 100_000_000; i++)
                    {
                        Show<int>(iValue);
                    }
                    watch.Stop();
                    genericSecond = watch.ElapsedMilliseconds;
                }
                Console.WriteLine("commonSecond={0},objectSecond={1},genericSecond={2}"
                    , commonSecond, objectSecond, genericSecond);
            }
        }

        #region PrivateMethod
        private static void ShowInt(int iParameter)
        {
            //do nothing
        }
        private static void ShowObject(object oParameter)
        {
            //do nothing
        }
        private static void Show<T>(T tParameter)
        {
            //do nothing
        }
        #endregion

    }
}

GenericTest.cs

namespace MyGeneric
{
    /// <summary>
    /// 泛型方法
    /// </summary>
    public class GenericTest
    {
        public static void Show<T>(T tParameter)
        {
            Console.WriteLine("This is {0},parameter={1},type={2}",
                typeof(CommonMethod), tParameter.GetType().Name, tParameter);
        }
    }

    /// <summary>
    /// 泛型类型  就是一个类型 满足多个类型的需求
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class GenericClass<T>
    { 

    }

    public class ChildClass<S, T> : GenericClass<S>, GenericInterface<T>
    {
    }

    public class ChildClass1 : GenericInterface<int>
    {
    }

    /// <summary>
    /// 泛型接口  就是一个接口 满足多个多个类型的需求
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public interface GenericInterface<T>
    {
    }

    /// <summary>
    /// 泛型委托 就是一个委托 满足多个多个类型的需求
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public delegate void Do<T>();


}

CommonMethod.cs

namespace MyGeneric
{
    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);
        }

    }
}

GenericConstraint.cs

namespace MyGeneric
{
    /// <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  //值类型约束 就只能传入值类型的参数(int、bool等)
        // 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关键字  
        }

        // 泛型约束的好处:
        // 加了约束以后可以获取更多的功能;(接口约束或基类约束)
        // 程序在调用的时候可以避免错误调用(泛型传入无限制,所以转换易报错)                 
       
    }
}

Program.cs

namespace MyGeneric
{
    /// <summary>
    /// 1 引入泛型:延迟声明
    /// 2 如何声明和使用泛型
    /// 3 泛型的好处和原理
    /// 4 泛型类、泛型方法、泛型接口、泛型委托
    /// 5 泛型约束
    /// 6 协变 逆变(选修)
    /// 7 泛型缓存(选修)
    ///  
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                // 欢迎大家来到.Net 高级班的Vip课程,我是Richard老师!
                // 今天是第十三期的第一次课:泛型
                //什么是泛型?
                //宽泛的,不确定的,就是不确定的类型 
                //List<string> intlist = new List<string>();

                // var i = 1234; // 语法糖


                Console.WriteLine(typeof(List<>));
                Console.WriteLine(typeof(Dictionary<,>));

                Console.WriteLine("欢迎来到.net高级班vip课程,今天是Richard老师给大家带来的泛型Generic");
                int iValue = 123;
                string sValue = "456";
                DateTime dtValue = DateTime.Now;
                object oValue = "789";

                Console.WriteLine("***********************Common***********************");
                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("***********************Generic***********************");
                // 泛型只有:泛型方法、泛型类、泛型接口、泛型委托 
                //泛型方法调用的时候,需要加上<>,而且需要指定具体的类型、指定的类型和传入的参数类型保持一致。

                CommonMethod.Show(iValue); //如果类型参数,可以通过参数类型推导出来,那么就可以省略
                                           /* CommonMethod.Show<int>(sValue);*/// 因为类型错了 
                CommonMethod.Show(sValue);
                CommonMethod.Show<DateTime>(dtValue);
                CommonMethod.Show<object>(oValue);

                //Monitor.Show();

                Console.WriteLine("***********************GenericCache***********************");
                //GenericCacheTest.Show();

                //泛型方法  一个方法满足多个类型的需求
                //泛型类   就是一个类 满足多个类型的需求
                //泛型接口 就是一个接口 满足多个多个类型的需求
                //泛型委托 就是一个委托 满足多个多个类型的需求

                //GenericConstraint.ShowObject(iValue);
                //GenericConstraint.ShowObject(sValue);
                //GenericConstraint.ShowObject(dtValue);
                //GenericConstraint.ShowObject(oValue);
                 
                Console.WriteLine("***********************GenericConstraint***********************");
                // 泛型约束的好处:
                // 加了约束以后可以获取更多的功能;
                // 程序在调用的时候可以避免错误调用   
                People people = new People()
                {
                    Id = 123,
                    Name = "Richard"
                };

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

选修:
GenericCacheTest.cs

namespace MyGeneric.Extend
{
    /// <summary>
    /// 泛型缓存 
    /// 泛型缓存作为选修,不做太多要求。大家学习了后面的内容之后,会渐渐明白。
    /// </summary>
    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>
    {
        private static string _TypeTime = "";
        static GenericCache()
        {
            Console.WriteLine("This is GenericCache 静态构造函数");
            _TypeTime = string.Format("{0}_{1}", typeof(T).FullName, DateTime.Now.ToString("yyyyMMddHHmmss.fff"));
        }    

        public static string GetCache()
        {
            return _TypeTime;
        }
    }


}

CCTest.cs

namespace MyGeneric.Extend
{
    /// <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);
        }
    }

}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-06-14 22:21:09  更:2022-06-14 22:27:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:31:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码