Flier's Sky

天空,蓝色的天空,眼睛看不到的东西,眼睛看得到的东西

导航

Type, RuntimeType and RuntimeTypeHandle

Posted on 2004-07-08 11:07  Flier Lu  阅读(1512)  评论(1编辑  收藏  举报
http://www.blogcn.com/user8/flier_lu/index.html?id=1635813&run=.06FE977

 Vijay 在其 BLog 上的一篇文章 A .NET Riddle 中提出了一个有趣的问题:
 
以下为引用:

     What is the only Type in .NET which has only a non-public constructor and the method body of which throws up a NotImplemented Exception. If so how is the type instance created then ?
 


     答案就是 System.RuntimeType 类型。Vijay 在接下来的一篇文章 .NET Riddle Redux - The Answer 中解释了为什么如此,并且介绍了 Rotor 中 RuntimeType 类型获得的方法。
     Rotor 中 System.RuntimeType 类型的构造函数(bclsystemRuntimeType.cs:59)代码如下:
 
以下为引用:

 internal sealed class RuntimeType : Type, ISerializable, ICloneable
 {
   // Prevent from begin created
   internal RuntimeType()
   {
     throw new NotSupportedException(Environment.GetResourceString(ResId.NotSupported_Constructor));
   }
 }
 


     正如前面那个谜语中所说,有一个内部构造函数但函数体直接抛出异常,因此不能直接构造。唯一能够获得此类型实例的方式是通过Object.GetType()等函数,由 CLR 创建。

     下面我们简单介绍一下,Type、RuntimeType 和 RuntimeTypeHandle 三个类型之间的关系。

     简单的说:Type 是一个表示类型的抽象类;RuntimeType 是 Type 针对载入类型信息的具体实现;RuntimeTypeHandle 则是类型唯一的抽象句柄。
 

以下为引用:

 namespace System
 {
   public struct RuntimeTypeHandle : ISerializable
   {
     private IntPtr m_ptr;

     //...
   }

   public abstract class Type : MemberInfo, IReflect
   {
     //...

     public abstract RuntimeTypeHandle TypeHandle
     {
       get;
     }

     public static RuntimeTypeHandle GetTypeHandle(Object o)
     {
       return RuntimeType.InternalGetTypeHandleFromObject(o);
     }

     public static Type GetTypeFromHandle(RuntimeTypeHandle handle)
     {
       return RuntimeType.GetTypeFromHandleImpl(handle);
     }

     //...
   }

   internal sealed class RuntimeType : Type, ISerializable, ICloneable
   {
     //...

     public override RuntimeTypeHandle TypeHandle
     { get { return InternalGetClassHandle(); } }

     [MethodImplAttribute(MethodImplOptions.InternalCall)]
     private extern RuntimeTypeHandle InternalGetClassHandle();

     [MethodImplAttribute(MethodImplOptions.InternalCall)]
     internal extern static RuntimeTypeHandle InternalGetTypeHandleFromObject(Object o);

     [MethodImplAttribute(MethodImplOptions.InternalCall)]
     public static extern Type GetTypeFromHandleImpl(RuntimeTypeHandle handle);

     //...
   }
 }
 



     Type 使用最为广泛,提供了完整的类型信息获取的接口,可以通过 C# 的 typeof 关键字或者 Object.GetType() 函数从类型和对象直接获取。但 Type 只是一个抽象类,需要通过子类实现其部分功能。除了常见的 RuntimeType 子类外,还有 System.Reflection 名字空间下的 TypeDelegator 和 System.Reflection.Emit 名字空间下的 EnumBuilder、TypeBuilder 和 SymbolType 从其直接继承。
     RuntimeType 是 System 名字空间的内部类,用于实现对普通类型的运行时信息提供代码。Type中很多抽象函数如 Type.GetMethodImpl 都是在 RuntimeType 中实现的。与 TypeBuilder 等不同,RuntimeType 是类型的运行时表现。
     RuntimeTypeHandle 是运行时类型的抽象句柄,结构内部实际上是一个 Unamanged 指针。可以使用 Type.GetTypeFromHandle() 函数、Type.TypeHandle 属性和 Type.GetTypeHandle() 函数,完成在类型句柄、类型和对象之间的双向转换。例如:
 
以下为引用:

 MyClass1 cls = new MyClass1();

 Debug.Assert(cls.GetType().TypeHandle.Equals(Type.GetTypeHandle(cls)));
 Debug.Assert(Type.GetTypeFromHandle(cls.GetType().TypeHandle) == typeof(MyClass1));
 



     从 Rotor 的实现代码上来看,Type 类型的实际构造基本上都是由 RuntimeType 类型通过 COMClass 类(vmComClass.cpp:260)完成的;而 RuntimeTypeHandle 则是类型方法表 MethodTable 类(vmClass.h:293)的指针的简单包装。
     获取 RuntimeTypeHandle 的函数 Type.GetTypeHandle() 实际上调用的是 RuntimeType.InternalGetTypeHandleFromObject 函数(bclsystemRuntimeType.cs:592);而此函数的内部实现被绑定(vmECall.cpp:515)到 COMClass::GetTHFromObject 函数(vmComClass.cpp:255)上;最终只是简单地返回对象的 MethodTable 指针。伪代码如下
 
以下为引用:

 void * COMClass::GetTHFromObject(Object* obj)
 {
   if(obj==NULL)
     FCThrowArgumentNull(L"obj");

   return obj->GetMethodTable();
 }
 



     因此在 Unmanaged C++ 中实际上可以直接通过 GetTypeHandle 返回的 RuntimeTypeHandle.Data 转换为地址指针,访问 MethodTable 类的数据。例如 MethodTable 第二个 DWORD 中保存着此对象的基本大小,可以在 VS.NET 调试环境的内存窗口中查看到。
     
     直接从类型获取 RuntimeTypeHandle 的 Type.InternalGetClassHandle 函数(bclsystemRuntimeType.cs:589),内部实现被绑定(vmECall.cpp:528)到 COMClass::GetClassHandle 函数(vmComClass.cs:1434)上,直接从类型的内部包装类 ReflectClass 类(vmReflectorWrap.h:212)中获取初始化时提供的类型句柄(MethodTable指针)。伪代码如下
 
以下为引用:

 void * COMClass::GetClassHandle(ReflectClassBaseObject* refThisUNSAFE)
 {  
   REFLECTCLASSBASEREF refThis = (REFLECTCLASSBASEREF) refThisUNSAFE;

   ReflectClass* pRC = (ReflectClass*) refThis->GetData();  

   TypeHandle ret = pRC->GetTypeHandle();
   
   return ret.AsPtr();
 }
 



     从 RuntimeTypeHandle 反向查询 Type 的 Type.GetTypeFromHandle 函数,实现上调用 RuntimeType.GetTypeFromHandleImpl 函数(bclsystemRuntimeType.cs:596),并被绑定(vmECall.cpp:529)到 COMClass::GetClassFromHandle 函数(vmComClass.cpp:1451)上。
     GetClassFromHandle 函数首先试图从 RuntimeTypeHandle 实例指向的方法表中,调用 MethodTable::GetExistingExposedClassObject 函数(vmClass.h:488)获取已经建立的类型信息包装类;如果第一次使用此类型,则调用 TypeHandle::CreateClassObj 函数(vmClass.cpp:12486)创建类型信息包装类实例。伪代码如下:
 
以下为引用:

 Object * COMClass::GetClassFromHandle(LPVOID handle)
 {
   if(handle == 0)
     FCThrowArgumentEx(kArgumentException, NULL, L"InvalidOperation_HandleIsNotInitialized");

   TypeHandle typeHnd(handle);

   if(!typeHnd.IsTypeDesc())
   {
     MethodTable *pMT = typeHnd.GetMethodTable();

     if (pMT)
     {
       OBJECTREF o = pMT->GetExistingExposedClassObject(); // 获取已经建立的类型信息包装类
       if (o != NULL)
       {
         return (OBJECTREFToObject(o));
       }
     }
   }

   return typeHnd.CreateClassObj(); // 创建类型信息包装类实例
 }