浅谈 MetadataToken

原文在这里

 

概念: 要说MetadataToken,首先的先说说Metadata,MSDN对Metadata的定义是这样的“Metadata refers to declarative information about abstractions, including runtime types (classes, value types, and interfaces),  global functions, and global variables.”  (这里就不做翻译了,怕翻译不好造成误解)而对于这些Runtime的类型信息存贮在Metadata的一张张表中,我们知道这些表有定义表、引用表、指针表、堆。那么MetadataToken是什么呢?MetadataToken其实就是这些存贮在Metadata一张张表中的位置信息,它指向的就是这些表中的一个记录。对于Metadata Engine 来说,可以用这些Token去定位具体的一个Runtime Type。

   深入:MetadataToken的结构就是一个4字节的int型整数,第一个字节指出这个MetadataToken指向的RuntimeType存贮在具体的哪一个Metadata表。 对于每个Metadata表的索引值由CorTokenType这个Enum来决定,CorTokenType的定义如下:

typedef  enum  CorTokenType {

    mdtModule                       
=   0x00000000 ,
    mdtTypeRef                      
=   0x01000000 ,
    mdtTypeDef                      
=   0x02000000 ,
    mdtFieldDef                     
=   0x04000000 ,
    mdtMethodDef                    
=   0x06000000 ,
    mdtParamDef                     
=   0x08000000 ,
    mdtInterfaceImpl                
=   0x09000000 ,
    mdtMemberRef                    
=   0x0a000000 ,
    mdtCustomAttribute              
=   0x0c000000 ,
    mdtPermission                   
=   0x0e000000 ,
    mdtSignature                    
=   0x11000000 ,
    mdtEvent                        
=   0x14000000 ,
    mdtProperty                     
=   0x17000000 ,
    mdtModuleRef                    
=   0x1a000000 ,
    mdtTypeSpec                     
=   0x1b000000 ,
    mdtAssembly                     
=   0x20000000 ,
    mdtAssemblyRef                  
=   0x23000000 ,
    mdtFile                         
=   0x26000000 ,
    mdtExportedType                 
=   0x27000000 ,
    mdtManifestResource             
=   0x28000000 ,
    mdtGenericParam                 
=   0x2a000000 ,
    mdtMethodSpec                   
=   0x2b000000 ,
    mdtGenericParamConstraint       
=   0x2c000000 ,
    mdtString                       
=   0x70000000 ,
    mdtName                         
=   0x71000000 ,
    mdtBaseType                     
=   0x72000000

} CorTokenType;

 具体每一个enum值代表什么我就不用说了,相比聪明的你一看就明白了。从CorTokenType的定义,机灵的读者会发现其实每个表里只能有16777216条记录。就mdtTypeDef来说,我们可不可以说在一个Module中我们最多只能定义16777216个type呢?!扯的有些远了,我们回到刚才的对MetadataToken结构的讨论。4字节的MetadataToken的后三个字节在其实就是一个RuntimeType在具体一个Metadata表中的位置,或者说是偏移量吧。 口说无凭,还是我们来点实际的吧!

   例子 : 我们建一个简单的Console工程就可以了,定义一下三个type:

using  System;
namespace  ConsoleApplication3
{
    
interface  IClass1
    {
        
void  Fun1();
    }
}


using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  ConsoleApplication3
{
    
class  Class1 : ConsoleApplication3.IClass1
    {
        
public   void  Fun1()
        {
        }
    }
}


using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.Runtime.Serialization;

namespace  ConsoleApplication3
{
    
class  Program
    {
        
static   void  Main( string [] args)
        {
            Console.WriteLine(
" typeof(Class1).MetadataToken = {0} " , Convert.ToString(
                                                                        
typeof (Class1).MetadataToken,  16 )
                                                                        );

            Console.WriteLine(
" typeof(IClass1).MetadataToken = {0} " , Convert.ToString(
                                                                      
typeof (IClass1).MetadataToken,  16 )
                                                                      );

            Console.WriteLine(
" typeof(Program).MetadataToken = {0} " , Convert.ToString(
                                                                      
typeof (Program).MetadataToken,  16 )
                                                                      );

            Console.Read();
        }
    }
}

 

我们先不要急着去Run它,我们可以用前面说的这些知识来分析,然后猜想一下结果。因为这三个都是类型,所以他们的MetadataToken的第一个字节肯定是0x020000, 因为这个项目里面只有三个类型,所以我想他们的MetadataToken肯定是0x0200002、0x02000003, 0x02000004(有一个很重要的忘说了,在每张Metadata表中的0位置是不包含数据的,MSDN说成为nil token, 0x02000001这个位置预留给了一个名为<Module>的特殊类型。程序中所有的全局字段和全局方法,其实都是这个<Module>类型的成员(这里多谢 Anders Liu 帮忙指正,谢谢)),现在我们可以看看结果了啊

和我们预计结果一致。其他的我就不举例了,有兴趣的朋友可以自己试试,这里要注意的是一点就是String类型的MetadataToken的后三个字节的代表的是这个string在Metadata string pool中的起始位置。

      应用: 讲了这么多了,到底这个东东有什么用呢?该怎么样用呢?对于一个已经build的程序集,它其中的Metadata已经固定了,也就是说它的MetadataToken是固定。这样的话,有的时候我们就可以直接通过这个MetadataToken去获得它的RuntimeType,这点在泛型和反射有的时候是非常有用的。具体的使用如下:

            Module currentModule  =  Assembly.GetExecutingAssembly().GetModules()[ 0 ];

            ModuleHandle currentModuleHandle 
=  currentModule.ModuleHandle;

            
int  token  =   typeof (Program).MetadataToken;

            RuntimeTypeHandle rth 
=  currentModuleHandle.GetRuntimeTypeHandleFromMetadataToken(token);

            Type currentType 
=  Type.GetTypeFromHandle(rth);

    

           就写到这了,其实Metadata还是很值得仔细学习一下,我现在了解的还是很肤浅,这里也只是抛砖引玉,希望得到高手的拍砖, 哈哈哈。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值