Leo Zhang

A simple man with my own ideal

Interface到底继承于Object吗?之我见

      今天和同事讨论了一个问题:Interface到底继承于Object吗?
      我看过的所有关于.Net的书都告诉我“所有符合CTS的类型都是继承于System.Object的”,那么理所当然
Interface也是继承于System.Object的,以下面代码为例:

 

    class Program
    {
        
static void Main(string[] args)
        {
            IATM account 
= new ATMMachine();
            account.GetMoney(
600);
            Console.WriteLine(account.ToString());

            Console.ReadKey();
        }
    }

    
public interface IATM
    {
        
void GetMoney(Decimal amount);
    }

    
public class ATMMachine : IATM
    {
        
private Decimal b;

        
public void GetMoney(Decimal amount)
        {
            b 
+= amount;
        }

        
public override string ToString()
        {
            
return String.Format("Getted Money = {0,6:C}", b);
        }
    }

 

      将代码编译以后用IL DASM反编译后查看IATMde IL代码,如下:
      .class interface public abstract auto ansi ConsoleApplication2.IATM
      {
      } // end of class ConsoleApplication2.IATM 
和其他类型做比较如:
      .class private auto ansi beforefieldinit ConsoleApplication2.Program
             extends [mscorlib]System.Object
      {
      } // end of class ConsoleApplication2.Program
      都有.Class这个标识,说明事实上Interface也是一个Class,只是它是一个特殊的Class,同时说明一个问题,
IATM接口并没有继承System.Object,否则就应该有extends [mscorlib]System.Object这句话。那么到底Interface
继承了什么呢?利用AL DASM 查看元数据文件(Ctrl+M)后有如下片段:其中02000003标识Interface:IATM,02000004标识Class:ATMMachine 
TypeDef #2 (02000003)
-------------------------------------------------------
TypDefName: ConsoleApplication2.IATM  (02000003)
Flags     : [Public] [AutoLayout] [Interface] [Abstract] [AnsiClass]  (000000a1)
Extends   : 01000000 [TypeRef] 
Method #1 (06000003) 
-------------------------------------------------------
MethodName: GetMoney (06000003)
Flags     : [Public] [Virtual] [HideBySig] [NewSlot] [Abstract]  (000005c6)
RVA       : 0x00000000
ImplFlags : [IL] [Managed]  (00000000)
CallCnvntn: [DEFAULT]
hasThis 
ReturnType: Void
1 Arguments
Argument #1:  ValueClass System.Decimal
1 Parameters
(1) ParamToken : (08000002) Name : amount flags: [none] (00000000)


TypeDef #3 (02000004)
-------------------------------------------------------
TypDefName: ConsoleApplication2.ATMMachine  (02000004)
Flags     : [Public] [AutoLayout] [Class] [AnsiClass] [BeforeFieldInit]  (00100001)
Extends   : 01000001 [TypeRef] System.Object
Field #1 (04000001)
-------------------------------------------------------
Field Name: b (04000001)
Flags     : [Private]  (00000001)
CallCnvntn: [FIELD]
Field type:  ValueClass System.Decimal

Method #1 (06000004) 
-------------------------------------------------------
MethodName: GetMoney (06000004)
Flags     : [Public] [Final] [Virtual] [HideBySig] [NewSlot]  (000001e6)
RVA       : 0x0000208f
ImplFlags : [IL] [Managed]  (00000000)
CallCnvntn: [DEFAULT]
hasThis 
ReturnType: Void
1 Arguments
Argument #1:  ValueClass System.Decimal
1 Parameters
(1) ParamToken : (08000003) Name : amount flags: [none] (00000000)
      注意Extends标识,它表明当前类型继承了什么类型,从这里也可以看出IATM没有继承System.Object,否则应该有Extends   : 01000001 [TypeRef] System.Object这句描述,
      01000000 [TypeRef] 是什么呢?我理解是什么都不继承,打开mscorlib.dll有如下元数据描述片段:
TypeDef #1 (02000002)
-------------------------------------------------------
TypDefName: System.Object  (02000002)
Flags     : [Public] [AutoLayout] [Class] [Serializable] [AnsiClass] [BeforeFieldInit]  (00102001)
Extends   : 01000000 [TypeRef] 
Method #1 (06000001) 
-------------------------------------------------------
MethodName: .ctor (06000001)
Flags     : [Public] [HideBySig] [ReuseSlot] [SpecialName] [RTSpecialName] [.ctor]  (00001886)
RVA       : 0x000020d0
ImplFlags : [IL] [Managed]  (00000000)
CallCnvntn: [DEFAULT]
hasThis 
ReturnType: Void
No arguments.
CustomAttribute #1 (0c000001)
-------------------------------------------------------
CustomAttribute Type: 06003055
CustomAttributeName: System.Runtime.ConstrainedExecution.ReliabilityContractAttribute :: instance void .ctor(value class System.Runtime.ConstrainedExecution.Consistency,value class System.Runtime.ConstrainedExecution.Cer)
Length: 12
Value : 01 00 03 00 00 00 01 00  00 00 00 00             >                <
ctor args: ( <can not decode> )
这里的Extends标识后的内容也是01000000 [TypeRef],所以我推出Interface和System.Object都没有继承于任何类型。
      实际上,这里的01000000(即0X01000000)是元数据标识(Metadata Token),它是个4-byte的值,最高位用来标识当前的元数据类型,例如:01代表该条元数据是一个TypeRef,02代表TypeDef,04代表FieldDef,06代表MethodDef,08代表 ParamDef,对于最低3位,简单的说可以看成当前元数据在元数据表中的索引(实际上元数据表的存储是很复杂的),例如0x0400001B代表这条元数据是一个Field,它在元数据表中的索引位置是第27行,那么从0X01000000可以看出,它表示的是当前元数据标识的类型是一个TypeRef并且它在元数据表中的索引位置是0,其实在元数据表的索引位置0处是不存储任何数据的,所以这样的标识被称作“Nil”标识。
      最后是一个疑问:
            IATM account = new ATMMachine();     IATM account;           (当然这样写会编译不通过,但是智能感知依然有效)
            account.GetMoney(600);                 或者         account.GetMoney(600);  
                             
      在IDE中敲入account.后会发现除了IATM中定义的GetMoney方法外还有ToString、GetType、Equals、GetHashCode这四个方法,那么现在明明是用IATM接口来访问对象,而IATM并没有Extends System.Object,所以这里智能感知应该只出现GetMoney这个方法才对,可是事实却不是这样,那么这是为什么呢?我也没有从元数据中找到答案,希望各位高手能指点一二。

      另外我做如下猜测:通过接口所能访问的应该只有Class或者Struct,而只要是托管代码中的类型,不管是Class还是Struct都是继承于System.Object的(Struct继承于System.ValueType,而System.ValueType继承于System.Object),因此以上四个方法总是对外公开的,所以account.后边出现的是5个方法而不是1个。 
      最后,通过修改元数据可以去掉Extends   : 01000000 ....然后编译成新的dll并且这个dll可用,我觉得这个时候的代码已经不是托管代码了,不符合CLS规范了,所以以此来推出并不是所有类型都继承于System.Object可能不太合适。

      

posted on 2009-07-15 13:36  Leo Zhang  阅读(3886)  评论(63编辑  收藏  举报

导航