技术开发 频道

接口映射的实现及原理


【IT168技术文档】

  没有接口的继承,它实现的方式如下:
.method public hidebysig instance void 方法() cil managed { // Code Size: 11 byte(s) .maxstack 1 L_0000: ldstr "\u6211\u53ea\u80fd\u591f\u4f7f\u7528 new \u6765\u5c4f\u853d\u5b83\uff0c\u4e0d\u8fc7\uff0c\u5728IDesign\u7684 \u7f16\u7a0b\u89c4\u8303\u4e2d\uff0c\u4e0d\u63a8\u8350\u7528 new\u3002" L_0005: call void [mscorlib]System.Console::WriteLine(string) L_000a: ret }
  而有接口的继承,实现方式是这样的:
.method private hidebysig newslot virtual final instance void Test.接口.方法() cil managed { .override Test.接口::方法 // Code Size: 11 byte(s) .maxstack 1 L_0000: ldstr "\u8fd9\u5c31\u53eb\u505a\u63a5\u53e3\u7684\u91cd\u6620 \u5c04\uff0c\u8fd9\u53ea\u662f\u6280\u5de7\u6027\u7684\u4e1c\u897f\u800c\u5df2\u3002" L_0005: call void [mscorlib]System.Console::WriteLine(string) L_000a: ret }
  在这里可以看出,有接口的继承实际上对“方法”进行override,但这个override是覆盖的接口的方法的实现成员,并非是类的方法成员。

  然后,我们继续看看在客户类中对两者进行调用的IL

  没有接口继承的IL
L_001d: newobj instance void Test.没有接口的继承::.ctor() //创建实例
L_0022: stloc.2
L_0023: ldloc.2
L_0024: callvirt instance void Test.没有接口的继承::方法()
  有接口继承的IL
L_003a: newobj instance void Test.有接口的继承::.ctor() //创建实例
L_003f: stloc.s 有接口的继承1
L_0041: ldloc.s 有接口的继承1
L_0043: callvirt instance void Test.基类::方法()

  如果是采取接口访问时,则状况如下:

  没有接口继承的IL
L_0029: newobj instance void Test.没有接口的继承::.ctor()
L_002e: stloc.3
L_002f: ldloc.3
L_0030: callvirt instance void Test.接口::方法()

  有接口继承的IL
L_0048: newobj instance void Test.有接口的继承::.ctor()
L_004d: stloc.s 接口3
L_004f: ldloc.s 接口3
L_0051: callvirt instance void Test.接口::方法()
----------------------------------------------------------------------------
  注意一下上面标记颜色的部分,可以看出,采用不同的访问方式,实现的结果并不尽相同。也就是说,针对接口实现了的方法,与类本身自带的实现,是两回事,这种情况很类似于采用new关键字进行创建一个新的同名成员方法时遭遇的问题。
结果之所以会不同,是由于访问的方式不同的原因,如果采用“基类”来访问,很明显,这里获得的就是基类的成员实现。也就是说,这也是多态的一种体现,但并非不可预知或不可控制的。

  看见有人说VB很难实现接口的映射,实际上并不是这样,要解释一下这个问题,这里不得不说一下,强类型的C#语法的含义。
  “基类 objBase = new 基类();” 这种语法,表示的是使用“基类”来访问新建的“基类”的实例,换而言之,“基类 objDevired = new 没有接口的继承();”表示的就是使用基类来访问新建的“没有接口的继承”的实例。
  接口的访问,也是如此,在原理上,将接口看作是一个十分特殊的抽象类,它与一般的抽象类的区别在于强制了成员的实现(接口的语法由编译器来验证的,在 CLR并未提供限制性机制),所以,在有一些设计模式中,也可以看到采用了接口-抽象类-具体类的方式来绕开这类强制成员实现的检查,从而提高灵活性。
  所以,VB.NET照样也可以完成接口映射,因为接口本身的实现机制仍旧是依赖于类的基本特征的。

  示例伪代码如下:
0
相关文章