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);
}
}
{
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 阅读(3908) 评论(63) 编辑 收藏 举报