zoukankan      html  css  js  c++  java
  • .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类型确实有性能影响,单并不罪大恶极,也不是不能用的,也要看程序所处的环境。

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

  • 相关阅读:
    juc原子类之五:AtomicLongFieldUpdater原子类
    DICOM:C-GET与C-MOVE对照剖析
    android createbitmap函数内存溢出,求解怎样进行处理out of memory溢出问题
    TRIZ系列-创新原理-32-改变颜色原理
    FP-Growth算法之频繁项集的挖掘(python)
    个人年终总结
    J2EE之ANT
    log4net 使用与配置 每天一份log文件
    Android 完美实现图片圆角和圆形(对实现进行分析)
    Unity3d修炼之路:载入一个预制体,然后为该对象加入组件,然后查找对象,得到组件。
  • 原文地址:https://www.cnblogs.com/renzhitian/p/6202917.html
Copyright © 2011-2022 走看看