• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

C#泛型学习笔记

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

   本笔记摘抄自:https://www.cnblogs.com/dotnet261010/p/9034594.html,记录一下学习过程以备后续查用。

    一、什么是泛型

    泛型是C#2.0推出的新语法,不是语法糖,而是2.0由框架升级提供的功能。泛型类就类似于一个模板,可以在需要时为这个模板传入任何我们需要的类型。

    二、为什么使用泛型

    下面代码演示输出几种类型的相关信息:

    class Program
    {
        /// <summary>
        /// 打印帮助类
        /// </summary>
        public class ShowHelper
        {
            /// <summary>
            /// ShowInt
            /// </summary>
            /// <param name="intParam"></param>
            public static void ShowInt(int intParam)
            {
                Console.WriteLine($"Class={typeof(ShowHelper).Name},Type={intParam.GetType().Name},Parameter={intParam}");
            }

            /// <summary>
            /// ShowString
            /// </summary>
            /// <param name="strParam"></param>
            public static void ShowString(string strParam)
            {
                Console.WriteLine($"Class={typeof(ShowHelper).Name},Type={strParam.GetType().Name},Parameter={strParam}");
            }

            /// <summary>
            /// ShowDateTime
            /// </summary>
            /// <param name="dtParam"></param>
            public static void ShowDateTime(DateTime dtParam)
            {
                Console.WriteLine($"Class={typeof(ShowHelper).Name},Type={dtParam.GetType().Name},Parameter={dtParam}");
            }
        }

        static void Main(string[] args)
        {
            #region 非泛型打印方式一
            ShowHelper.ShowInt(123);
            ShowHelper.ShowString("Hello World.");
            ShowHelper.ShowDateTime(DateTime.Now);
            Console.Read();
            #endregion
        }
    }
View Code

    运行结果如下:

    上面3个方法很相似,除了参数类型不同外,实现的功能是一样的,可以稍作优化。

    下面代码演示使用继承的方式输出几种类型的相关信息:

    class Program
    {
        /// <summary>
        /// 打印帮助类
        /// </summary>
        public class ShowHelper
        {
            /// <summary>
            /// ShowType
            /// </summary>
            /// <param name="obj"></param>
            public static void ShowType(object obj)
            {
                Console.WriteLine($"Class={typeof(ShowHelper).Name},Type={obj.GetType().Name},Parameter={obj}");
            }
        }

        static void Main(string[] args)
        {
            #region 非泛型打印方式二
            ShowHelper.ShowType(123);
            ShowHelper.ShowType("Hello World.");
            ShowHelper.ShowType(DateTime.Now);
            Console.Read();
            #endregion
        }
    }
View Code

    功能实现没有问题,只是object与其它类型的转换,涉及到装箱和拆箱的过程,这个是会损耗程序的性能的。

    三、泛型类型参数

    在泛型类型或方法的定义中,泛型类型参数可认为是特定类型的占位符。

    下面代码演示使用泛型的方式输出几种类型的相关信息:

    class Program
    {
        /// <summary>
        /// 打印帮助类
        /// </summary>
        public class ShowHelper
        {
            /// <summary>
            /// Show
            /// </summary>
            /// <param name="obj"></param>
            public static void Show<T>(T tParam)
            {
                Console.WriteLine($"Class={typeof(ShowHelper).Name},Type={tParam.GetType().Name},Parameter={tParam}");
            }
        }

        static void Main(string[] args)
        {
            #region 泛型打印方式
            ShowHelper.Show(123);
            ShowHelper.Show("Hello World.");
            ShowHelper.Show(DateTime.Now);
            Console.Read();
            #endregion
        }
    }
View Code

    运行结果如下:

    1、为什么泛型可以解决上面的问题呢?

    泛型是延迟声明的:即定义的时候没有指定具体的参数类型,把参数类型的声明推迟到调用的时候才给它指定。 

    2、泛型究竟是如何工作的呢?

    程序执行原理:控制台程序最终会编译成一个exe程序。当exe被点击的时候,会经过JIT(即时编译器)的编译,最终生成二进制代码才能被计算机执行。

    泛型工作原理:泛型加入到语法以后,VS自带的编译器做了升级,升级之后编译时若遇到泛型,会做特殊的处理:生成占位符。然后经过JIT编译的时候,会把上面编译生成的占位符替换成具体的数据类型。

    下面代码演示泛型占位符:

    class Program
    {
        static void Main(string[] args)
        {
            #region 泛型占位符
            Console.WriteLine(typeof(List<>));
            Console.WriteLine(typeof(Dictionary<,>));
            Console.Read();
            #endregion
        }
    }
View Code

    运行结果如下:

    3、泛型性能问题

    下面代码演示泛型性能测试:

    class Program
    {
        static void Main(string[] args)
        {
            #region 泛型性能测试
            long commonTime = 0;
            long objectTime = 0;
            long genericTime = 0;
            Stopwatch watch = new Stopwatch();
            watch.Start();
            for (int i = 0; i < 10000; i++)
            {
                ShowHelper.ShowInt(123);
            }
            watch.Stop();
            commonTime = watch.ElapsedMilliseconds;

            watch.Reset();
            watch.Start();
            for (int i = 0; i < 10000; i++)
            {
                ShowHelper.ShowType(123);
            }
            watch.Stop();
            objectTime = watch.ElapsedMilliseconds;

            watch.Reset();
            watch.Start();
            for (int i = 0; i < 10000; i++)
            {
                ShowHelper.Show(123);
            }
            watch.Stop();
            genericTime = watch.ElapsedMilliseconds;

            Console.Clear();
            Console.WriteLine($"Common time={commonTime}ms");
            Console.WriteLine($"Object time={objectTime}ms");
            Console.WriteLine($"Generic time={genericTime}ms");
            Console.Read();
            #endregion
        }
    }
View Code

    运行结果如下:

    从结果可以看出,泛型的性能是最高的。

    四、泛型类

    下面代码演示泛型类:

    class Program
    {
        /// <summary>
        /// 泛型类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public class GenericClass<T>
        {
            public T varT;
        }

        static void Main(string[] args)
        {
            #region 泛型类
            //T是int类型
            GenericClass<int> genericInt = new GenericClass<int>
            {
                varT = 123
            };
            Console.WriteLine($"The value of T={genericInt.varT}");
            //T是string类型
            GenericClass<string> genericString = new GenericClass<string>
            {
                varT = "123"
            };
            Console.WriteLine($"The value of T={genericString.varT}");
            Console.Read();
            #endregion
        }
    }
View Code

    运行结果如下:

    五、泛型接口

    注:泛型在声明的时候可以不指定具体的类型,继承的时候也可以不指定具体类型,但是在使用的时候必须指定具体类型。

    下面代码演示泛型接口:

    class Program
    {
        /// <summary>
        /// 泛型接口
        /// </summary>
        public interface IGenericInterface<T>
        {
            T GetT(T t);
        }

        /// <summary>
        /// 泛型接口实现类
        /// </summary>
        /// <param name="args"></param>
        public class GenericGet<T> : IGenericInterface<T>
        {
            T varT;
            public T GetT(T t)
            {
                varT = t;
                return varT;
            }
        }

        static void Main(string[] args)
        {
            #region 泛型接口
            IGenericInterface<int> genericInterface = new GenericGet<int>();
            var result = genericInterface.GetT(123);
            Console.WriteLine($"Result={result}");
            Console.Read();
            #endregion
        }
    }
View Code

    运行结果如下:

    六、泛型委托

    下面代码演示泛型委托:

    class Program
    {
        /// <summary>
        /// 泛型委托
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public delegate void SayHi<T>(T t);

        static void Main(string[] args)
        {
            #region 泛型委托
            SayHi<string> sayHi = SayHello;
            sayHi("Hello World");
            Console.Read();
            #endregion
        }

        /// <summary>
        /// SayHello
        /// </summary>
        /// <param name="greeting"></param>
        public static void SayHello(string greeting)
        {
            Console.WriteLine($"{greeting}");
        }
    }
View Code

    运行结果如下:

    七、泛型约束

    泛型约束,实际上就是约束的类型T,使T必须遵循一定的规则。比如T必须继承自某个类或者T必须实现某个接口等等。

    怎样给泛型指定约束?其实也很简单,只需要where关键字,加上约束的条件。

    泛型约束总共有五种:

约束 s说明
T:结构 类型参数必须是值类型
T:类 类型参数必须是引用类型;这一点也适用于任何类、接口、委托或数组类型。
T:new() 类型参数必须具有无参数的公共构造函数。 当与其他约束一起使用时,new() 约束必须最后指定。
T:<基类名> 类型参数必须是指定的基类或派生自指定的基类。
T:<接口名称> 类型参数必须是指定的接口或实现指定的接口。 可以指定多个接口约束。 约束接口也可以是泛型的。

    7.1基类约束

    下面代码演示基类约束:

        /// <summary>
        /// 运动类接口
        /// </summary>
        public interface ISports
        {
            void Pingpong();
        }

        /// <summary>
        /// 人类基类
        /// </summary>
        public class People
        {
            public string Name { get; set; }

            public virtual void Greeting()
            {
                Console.WriteLine("Hello World.");
            }
        }

        /// <summary>
        /// 中国人
        /// </summary>
        public class Chinese : People, ISports
        {
            public void FineTradition()
            {
                Console.WriteLine("自古以来,中华民族就保持着勤劳的优良传统。");
            }
            public override void Greeting()
            {
                Console.WriteLine("吃饭了没?");
            }

            public void Pingpong()
            {
                Console.WriteLine("乒乓球是中国的国球。");
            }
        }

        static void Main(string[] args)
        {
            #region 泛型约束:基类约束
            Chinese chinese = new Chinese()
            {
                Name = "中国人"
            };
            ShowPeople(chinese);
            Console.Read();
            #endregion
        }

        /// <summary>
        /// 基类约束
        /// </summary>
        /// <param name="obj"></param>
        public static void ShowPeople<T>(T tParam) where T:People
        {
            Console.WriteLine($"{((People)tParam).Name}");
        }
    }
View Code

    运行结果如下:

    注:基类约束时,基类不能是密封类,即不能是sealed类。sealed类表示该类不能被继承,在这里用作约束就无任何意义了,因为sealed类没有子类。

    7.2接口约束

    下面代码演示接口约束:

    class Program
    {
        /// <summary>
        /// 运动类接口
        /// </summary>
        public interface ISports
        {
            void Pingpong();
        }

        /// <summary>
        /// 人类基类
        /// </summary>
        public class People
        {
            public string Name { get; set; }

            public virtual void Greeting()
            {
                Console.WriteLine("Hello World.");
            }
        }

        /// <summary>
        /// 中国人
        /// </summary>
        public class Chinese : People, ISports
        {
            public void FineTradition()
            {
                Console.WriteLine("自古以来,中华民族就保持着勤劳的优良传统。");
            }
            public override void Greeting()
            {
                Console.WriteLine("吃饭了没?");
            }

            public void Pingpong()
            {
                Console.WriteLine("乒乓球是中国的国球。");
            }
        }

        static void Main(string[] args)
        {
            #region 泛型约束:接口约束
            Chinese chinese = new Chinese()
            {
                Name = "中国人"
            };
            GetSportsByInterface(chinese);
            Console.Read();
            #endregion
        }

        /// <summary>
        /// 接口约束
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static T GetSportsByInterface<T>(T t) where T : ISports
        {
            t.Pingpong();
            return t;
        }
    }
View Code

    运行结果如下:

    7.3引用类型约束 class

    引用类型约束保证T一定是引用类型的。

    下面代码演示引用类型约束:

    class Program
    {
        /// <summary>
        /// 运动类接口
        /// </summary>
        public interface ISports
        {
            void Pingpong();
        }

        /// <summary>
        /// 人类基类
        /// </summary>
        public class People
        {
            public string Name { get; set; }

            public virtual void Greeting()
            {
                Console.WriteLine("Hello World.");
            }
        }

        /// <summary>
        /// 中国人
        /// </summary>
        public class Chinese : People, ISports
        {
            public void FineTradition()
            {
                Console.WriteLine("自古以来,中华民族就保持着勤劳的优良传统。");
            }
            public override void Greeting()
            {
                Console.WriteLine("吃饭了没?");
            }

            public void Pingpong()
            {
                Console.WriteLine("乒乓球是中国的国球。");
            }
        }

        static void Main(string[] args)
        {
            #region 泛型约束:引用类型约束
            Chinese chinese = new Chinese()
            {
                Name = "中国人"
            };
            GetSportsByClass(chinese);
            Console.Read();
            #endregion
        }

        /// <summary>
        /// 引用类型约束
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static T GetSportsByClass<T>(T t) where T : class
        {
            if (t is ISports)
            {
                (t as ISports).Pingpong();
            }
            return t;
        }
    }
View Code

    运行结果如下:

    7.4值类型约束 struct

    值类型约束保证T一定是值类型的。

    下面代码演示值类型约束:

    class Program
    {
        /// <summary>
        /// 绩效工资
        /// </summary>
        public struct Achievement
        {
            public double MeritPay { get; set; }
            public string Level { get; set; }
            public double ReallyPay()
            {
                switch (Level)
                {
                    case "A":
                        MeritPay = MeritPay * 1.0;
                        break;
                    case "B":
                        MeritPay = MeritPay * 0.8;
                        break;
                    case "C":
                        MeritPay = MeritPay * 0.6;
                        break;
                    case "D":
                        MeritPay = 0;
                        break;
                    default:
                        MeritPay = 0;
                        break;
                };
                return MeritPay;
            }
        }

        static void Main(string[] args)
        {
            #region 泛型约束:值类型约束
            Achievement achievement = new Achievement
            {
                MeritPay = 500,
                Level = "B"
            };
            var result = GetReallyPay(achievement).ReallyPay();
            Console.WriteLine($"ReallyPay={result}");
            Console.Read();
            #endregion
        }

        /// <summary>
        /// 值类型约束
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static T GetReallyPay<T>(T t) where T : struct
        {
            return t;
        }
    }
View Code

    运行结果如下:

    7.5无参数构造函数约束 new() 

    下面代码演示无参数构造函数约束:

    class Program
    {
        /// <summary>
        /// 运动类接口
        /// </summary>
        public interface ISports
        {
            void Pingpong();
        }

        /// <summary>
        /// 人类基类
        /// </summary>
        public class People
        {
            public string Name { get; set; }

            public virtual void Greeting()
            {
                Console.WriteLine("Hello World.");
            }
        }

        /// <summary>
        /// 中国人
        /// </summary>
        public class Chinese : People, ISports
        {
            public void FineTradition()
            {
                Console.WriteLine("自古以来,中华民族就保持着勤劳的优良传统。");
            }
            public override void Greeting()
            {
                Console.WriteLine("吃饭了没?");
            }

            public void Pingpong()
            {
                Console.WriteLine("乒乓球是中国的国球。");
            }
        }

        /// <summary>
        /// 广东人
        /// </summary>
        public class Guangdong : Chinese
        {
            public Guangdong() { }
            public string Dialect { get; set; }
            public void Mahjong()
            {
                Console.WriteLine("这麻将上瘾的时候,一个人也说是三缺一呀。");
            }
        }

        static void Main(string[] args)
        {
            #region 泛型约束:无参数构造函数约束
            Guangdong guangdong = new Guangdong()
            {
                Name = "广东人"
            };
            GetMahjong(guangdong);
            Console.Read();
            #endregion
        }

        /// <summary>
        /// 无参数构造函数约束
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public static T GetMahjong<T>(T t) where T : People, ISports, new()
        {
            if (t is
                      

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap