代码之家  ›  专栏  ›  技术社区  ›  Jeff Moser

为什么C编译器要插入显式接口实现?

  •  31
  • Jeff Moser  · 技术社区  · 14 年前

    我遇到了一个奇怪的C边缘案件,正在寻找一个良好的工作。

    有一个类是我无法控制的,它如下所示:

    namespace OtherCompany
    {
        public class ClassIDoNotControl
        {
            public void SomeMethod(string argument)
            {
                Console.WriteLine((new StackFrame(1).GetMethod().Name));
            }
        }
    }
    

    我想从这个阶级继承一个阶级 控制。另外,我想在上面指定一个接口:

    interface IInterfaceIDoControl
    {
        void SomeMethod(string argument);
    }
    
    class ClassIDoControl : OtherCompany.ClassIDoNotControl, IInterfaceIDoControl
    {
    }
    

    如果所有这些文件都在同一程序集中,那么一切都会很好地工作:

    namespace MyCompany
    {
        class Program
        {
            static void Main(string[] args)
            {
                IInterfaceIDoControl i = new ClassIDoControl();
                i.SomeMethod("Hello World!"); // Prints "Main"
            }
        }
     }
    

    但是,如果我将“ClassidNotControl”移动到另一个程序集中,我就无法得到我所期望的。相反,我看到输出的“mycompany.iInterfaceIdocontrol.someMethod”,它意味着一个额外的堆栈帧。

    原因是,在封面下,C编译器将“classidocontrol”更改为如下所示:

    class ClassIDoControl : OtherCompany.ClassIDoNotControl, IInterfaceIDoControl
    {
        void IInterfaceIDoControl.SomeMethod(string argument)
        {
            base.SomeMethod(argument);
        }
    }
    

    有没有一种方法可以避免这个编译器生成带有显式实现接口的额外间接层?

    1 回复  |  直到 14 年前
        1
  •  43
  •   Jeff Moser    14 年前

    简短回答: clr要求实现接口方法的所有方法都必须是虚拟的( Ecma 335 Partition II 第12.1节)

    长回答:

    • 如果基类中的方法已经是虚拟的,那么不需要任何额外的东西:接口方法可以绑定到它。

    • 如果基类中的方法是 虚拟的,但在同一个程序集中,秘密的编译器实际上 使其成为虚拟的和最终的 . 反射镜证实了这一点。 (_156;final_157;是C_中__sealed_157;的CLR术语。)

    • 如果基类中的方法不是虚拟的,并且在另一个程序集中,那么显然编译器可以做到这一点,因为它不能修改已经编译的程序集。因此,这里唯一的选项是插入实现接口方法的重定向方法。与实现接口方法的所有方法一样,它也被标记 虚拟和最终 .

    最后一个问题的答案是,有没有办法避免这个问题?不幸的是,不是。