.NET泛型初探

总所周知,.NET出现在.net framework 2.0,为什么要在2.0引入泛型那,因为微软在开始开发.net框架时并没有想过多个类型参数传输时对方法的重构,这样一来,开发人员就要面对传输多种类型的参数而不得以写多个方法,但是,开发者的智慧是无限的,创造性也由此被挖掘出来,在泛型之前,便有开发者为了提到代码利用率便想到使用object类型为参数类型来传递参数,这无疑解决了多个类型的参数传输时并需要写多个方法的问题。那么object类型为什么能实现接受多个不同类型的参数那?有了object类型还为什么要设计泛型那?object类型又有那么弊端那?其实有点基础的开发人员应该都知道object类型是所有类型的父类,通过里氏转换原则我们知道所有父类出现的地方都可以用子类替换,这样就可以接收多个参数了,同时因为object类型转换装拆箱对性能的影响,在2.0时,微软推出了泛型。

下面,我们引入泛型的声明和调用:

1    public static void Show<T>(T tParameter)
2       {
3            Console.WriteLine($"This is{typeof(GenericClass)}Show<T>,paratype={tParameter.GetType()},value={tParameter}");
4       }

打印的内容我们没必要关注,我们只看方法头,我们可以看到方法头和参数里面加了T这个字母,其实这就是泛型声明的规则,泛型在声明时,需要在方法头加上<T>(T parm),
注意,尖括号里面的字母是可变的,可以是任何字母,但是尖括号里面的字母必须和参数里面的字母要一致,这样一个方法就声明好了。

下面我们接下来研究下泛型的调用过程,泛型是如何在未命名参数类型的情况下来声明参数类型的,在下面程序入口我写了两个List的类型

1   class Program
2     {
3         static void Main(string[] args)
4         {
5             try
6             {
7
8                 Console.WriteLine(typeof(List<int>));
9                 Console.WriteLine(typeof(List<string>));

运行我们发现,TList虽然在调用时不知道传的什么类型,但是加了占位符,那么占位符是什么那?我们从dos里面看到`1,对,这个就是占位符。那么定位符是在什么时候声明的那?上代码

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                int iParameter = 123;
                long lParameter = 456;
                string sParameter = "abc";
                object oParameter = "123456";

                Console.WriteLine("**********************");
                CommonClass.ShowInt(iParameter);
                CommonClass.ShowLong(lParameter);
                CommonClass.ShowString(sParameter);

                Console.WriteLine("**********************");
                CommonClass.ShowObject(oParameter);
                CommonClass.ShowObject(iParameter);
                CommonClass.ShowObject(lParameter);
                CommonClass.ShowObject(sParameter);

                Console.WriteLine("**********************");
                GenericClass.Show<object>(oParameter);
                GenericClass.Show<int>(iParameter);
                //GenericClass.Show<int>(lParameter);//指定类型必须和参数一致
                GenericClass.Show(iParameter);//不指定,由编译器自动推算
                GenericClass.Show<long>(lParameter);
                GenericClass.Show<string>(sParameter);

                Console.WriteLine("**********************");
             }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.Read();
        }
    }
}

这里我就不赘述了,直接说一下吧,其实泛型在声明的时候不知道什么类型(用了占位符),是在调用的时候编译器自动推算,也可以在调用时指定,这是一种延迟思想延迟声明:把参数类型的声明,延迟到调用的时候,推迟一切可以推迟的,这也是设计模式的一种思想。编译以后的泛型和普通方法就一样了,所以不会影响性能,可以想象成又一个重载

泛型的好处:一个方法支持多种参数类型 ,性能无损耗。

泛型支持多个参数可想而知,但是真的无损耗吗?不清楚,好,对一切我们要持一种怀疑的态度去看,科学的自然会被证实,那么这里我们测试一下。用到类:Stopwatch

 1                 long commonTime = 0;
 2                 long objectTime = 0;
 3                 long genericTime = 0;
 4                 {
 5                     Stopwatch watch = new Stopwatch();
 6                     watch.Start();
 7                     for (int i = 0; i < 100000000; i++)
 8                     {
 9                         CommonClass.ShowObject(iParameter);
10                     }
11                     watch.Stop();
12                     objectTime = watch.ElapsedMilliseconds;
13                 }
14                 {
15                     Stopwatch watch = new Stopwatch();
16                     watch.Start();
17                     for (int i = 0; i < 100000000; i++)
18                     {
19                         CommonClass.ShowInt(iParameter);
20                     }
21                     watch.Stop();
22                     commonTime = watch.ElapsedMilliseconds;
23                 }
24                 {
25                     Stopwatch watch = new Stopwatch();
26                     watch.Start();
27                     for (int i = 0; i < 100000000; i++)
28                     {
29                         GenericClass.Show<int>(iParameter);
30                     }
31                     watch.Stop();
32                     genericTime = watch.ElapsedMilliseconds;
33                 }
34                 Console.WriteLine("commonTime={0}", commonTime);
35                 Console.WriteLine("objectTime={0}", objectTime);
36                 Console.WriteLine("genericTime={0}", genericTime);

里面的三个类分别是object类型和普通类以及泛型,分别对int、string以及实体类型的调用,我直接上答案:

通过图上给出的运行时间,泛型是最快的,然后是普通方法,然后是object类型,大家要知道,我这是在运行1亿次的情况下的所得的结果,其实,我们还得出一个结论,那就是,object类型确实有性能影响,单并不罪大恶极,也不是不能用的,也要看程序所处的环境。

补充一点,泛型不是语法糖,语法糖是编译器提供带的功能,不要误解了。

时间: 2024-10-10 10:01:14

.NET泛型初探的相关文章

泛型初探

泛型初探 在泛型(Generic type或Generics)出现之前,是这么写代码的: public static void main(String[] args) { List list = new ArrayList(); list.add("123"); list.add("456"); System.out.println((String)list.get(0)); } 当然这是完全允许的,因为List里面的内容是Object类型的,自然任何对象类型都可以

C# 泛型初探

初探的类: public class TClass { /// <summary> /// int参数 /// </summary> /// <param name="iParameter"></param> public static void ShowInt(int iParameter) { Console.WriteLine("这里是TClass ShowInt{0},类型为{1}",iParameter,iP

Java泛型初探

在做安卓项目中看到别人写的基类里各种用到泛型,能够看懂并使用.感觉对于Java学习还是很重要的一块,在以后的code生涯中会遇到很多,所以刷个博客作为学习笔记. 泛型(Template)比如你在写基类或者API之类的时候,由于Java是强类型语言,所以无法预料到将来继承你写的基类的人会用什么类型的数据,比如String.Integer或者是他自己定义的类.因此,泛型横空出世(这里全是我自己的见解,到底为什么出现泛型我也没有去查).接下来举个实例,应该就比较好了解泛型的作用和使用了. 1 clas

Java语法糖3:泛型

泛型初探 在泛型(Generic type或Generics)出现之前,是这么写代码的: public static void main(String[] args) { List list = new ArrayList(); list.add("123"); list.add("456"); System.out.println((String)list.get(0)); } 当然这是完全允许的,因为List里面的内容是Object类型的,自然任何对象类型都可以

Java语法糖(3):泛型

泛型初探 在泛型(Generic type或Generics)出现之前,是这么写代码的: public static void main(String[] args){List list = new ArrayList();list.add("123");list.add("456"); System.out.println((String)list.get(0));}当然这是完全允许的,因为List里面的内容是Object类型的,自然任何对象类型都可以放入.都可以

唬人的Java泛型并不难

摘自:https://www.cnblogs.com/tonyY/p/12200121.html 泛型 public interface Foo<E> {} public interface Bar<T> {} public interface Zar<?> {} 上面的代码有什么区别? 泛型初探 1.为何引入泛型? Java 泛型也是一种语法糖,使用泛型可以在代码编译阶段完成类型的转换,避免代码在运行时强制转换而出现ClassCastException的异常. 网络搜

Java之集合初探(二)Iterator(迭代器),collections,打包/解包(装箱拆箱),泛型(Generic),comparable接口

Iterator(迭代器) 所有实现了Collection接口的容器都有一个iterator方法, 用来返回一个实现了Iterator接口的对象 Iterator对象称作迭代器, 用来方便的实现对容器内的元素的遍历 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构.迭代器通常被称为"轻量级"对象,因为创建它的代价小. Java中的Iterator功能比较简单,并且只能单向移动: (1) 使用方法iterator()要求容器返回一个I

Unity3D游戏开发初探

一.预备知识-对象的"生"与"死" (1)如何在游戏脚本程序中创建对象而不是一开始就创建好对象?->使用GameObject的静态方法:CreatePrimitive() 以上一篇的博文中的"指哪打哪"例子为基础,在AddForce脚本写入以下代码:   其中在CreateCube方法中,使用GameObject.CreatePrimitive方法来创建Cube类型的游戏对象实例,设置了它出现的坐标并为它增加刚体组件.这里可以看下AddCo

C#多线程之旅(4)——APM初探

原文地址:C#多线程之旅(4)——APM初探 C#多线程之旅目录: C#多线程之旅(1)——介绍和基本概念 C#多线程之旅(2)——创建和开始线程 C#多线程之旅(3)——线程池 C#多线程之旅(4)——APM初探 C#多线程之旅(5)——同步机制介绍 C#多线程之旅(6)——详解多线程中的锁 更多文章正在更新中,敬请期待...... C#多线程之旅(4)——APM初探 v博客前言 先交代下背景,前面几张内容主要是介绍多线程的基本知识,这一章是因为正好接触到了APM(异步编程模型),发现APM真