• 详解C#泛型(三)


      一、前面两篇文章分别介绍了定义泛型类型、泛型委托、泛型接口以及声明泛型方法:

      详解C#泛型(一)

      详解C#泛型(二)

      首先回顾下如何构建泛型类:

    public class MyClass<T>
    {
        public void MyFunc()
        {
            //
        }
    }

      其中,尖括号<>中的T代表的是该泛型类的类型参数,在使用时可以指定其类型,例如,指定类型参数为整数类型,创建封闭式构造类MyClass<int>:

    MyClass<int> myObj = new MyClass<int>();

      二、这一篇我们了解一下泛型的作用机制,泛型是运行时起作用的一套机制,根据运行时类型参数被指定为值类型还是引用类型其使用方式有所不同:

      1.当类型参数被指定为值类型时,会在第一次指定该特定值类型的类型时创建该类型唯一的专用化泛型类型,泛型类型中的类型参数会被替换为相应的值类型;

      ※此时,运行时会创建不同封闭式构造类型的类型信息对象,它们的类型句柄指向不同的类型信息对象,不同封闭式构造类型的方法句柄也指向不同的方法信息对象;

      2.当类型参数被指定为引用类型时,会在第一次指定任意引用类型时创建一个通用化泛型类型,泛型类型中的类型参数会被替换为该引用类型,并在之后每次指定为引用类型时重用该泛型类型并修改其中类型参数的类型;造成这种差异的原因可能在于所有的引用大小相同;

      ※此时,运行时依然会创建不同封闭式构造类型的类型信息对象,它们的类型句柄也指向不同的类型信息对象,但是它们共用一套方法句柄,即不同封闭式构造类型的方法句柄指向同一个方法信息对象;
      3.对于给定的泛型类:

    public class MyClass<T>
    {
        public void MyFunc()
        {
            //…
        }
    }
    获取不同封闭式构造类型的类型句柄和方法句柄:
    Type type1 = typeof(MyClass<int>);
    Type type2 = typeof(MyClass<long>);
    Type type3 = typeof(MyClass<string>);
    Type type4 = typeof(MyClass<Array>);
    //以下类型句柄各不相同
    Console.WriteLine(type1.TypeHandle.Value);
    Console.WriteLine(type2.TypeHandle.Value);
    Console.WriteLine(type3.TypeHandle.Value);
    Console.WriteLine(type4.TypeHandle.Value);
    //最后两个方法句柄相同,其它方法句柄各不相同
    Console.WriteLine(type1.GetMethod("MyFunc").MethodHandle.Value);
    Console.WriteLine(type2.GetMethod("MyFunc").MethodHandle.Value);
    Console.WriteLine(type3.GetMethod("MyFunc").MethodHandle.Value);
    Console.WriteLine(type4.GetMethod("MyFunc").MethodHandle.Value);

      ※在访问任何泛型类型之前,CLR会先创建MyClass<>的类型信息对象;

      打印结果:

      

      可以发现,最后两个泛型类型的MyFunc方法的方法句柄指向相同;但是不同类型参数的情况下,还是会创建对应的泛型类型对象,这使得泛型单例成为可能:

      三、对于封闭式构造类型,只要其类型参数不完全相同,CLR就会在初次访问该类型之前创建该类型的类型信息对象并调用其对应唯一的静态构造函数,例如对于有静态构造函数的泛型类MyClass<T>,在初次访问MyClass<int>、MyClass<string>等封闭式构造类之前都会调用一次其对应唯一的静态构造函数,这也是创建泛型单例的基础:

    public class MyClass<T>
    {
        static MyClass()
        {
            Console.WriteLine(typeof(T).FullName);
        }
    }
    MyClass<int> obj1 = new MyClass<int>();
    MyClass<long> obj2 = new MyClass<long>();
    MyClass<Array> obj4 = new MyClass<Array>();  

      打印结果:

      

      四、运行时动态构建泛型:

    Type myType = typeof(MyClass<>);  //获取未指定任何类型参数的开放式构造类的类型信息,多个类型参数时添加,:typeof(MyClass<,>)
    myType = myType.MakeGenericType(typeof(int));  //通过类型信息的实例方法MakeGenericType()构建指定所有类型参数的封闭式构造类的类型信息,如未指定所有类型参数会抛出异常ArgumentException
    //也可以直接获取封闭式构造类的类型信息,当类型参数在一开始就确定时推荐使用此种方式
    //myType = typeof(MyClass<int>);  //多个类型参数时需要同时指定:typeof(MyClass<int, string>)

      注意:通过反射只可以获取未指定任何类型参数的开放式构造类MyClass<,>的类型信息和指定所有类型参数的封闭式构造类MyClass<int, string>的类型信息,即无法获取MyClass<int, >的类型信息;


    如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的认可是我写作的最大动力!

    作者:Minotauros
    出处:https://www.cnblogs.com/minotauros/

    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    Flex动画
    八大排序算法
    Android switch语句“case expressions must be constant expressions”
    MySQL修改root密码的多种方法
    Android中ListView控件onItemClick事件中获取listView传递的数据
    超详细Android接入支付宝支付实现,有图有真相
    Android蓝牙开发---与蓝牙模块进行通信
    Leecode no.19 删除链表的倒数第 N 个结点
    玩转java静态/动态代理
    Leecode no.198. 打家劫舍
  • 原文地址:https://www.cnblogs.com/minotauros/p/10006796.html
Copyright © 2020-2023  润新知