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

Jef*_*ser 31 c# compiler-construction

我遇到了一个奇怪的C#边缘案例,我正在寻找一个好的解决方案.

有一个我无法控制的类看起来像这样:

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

我想从这个类中的一类我继承控制.另外,我想在其上指定一个接口:

interface IInterfaceIDoControl
{
    void SomeMethod(string argument);
}

class ClassIDoControl : OtherCompany.ClassIDoNotControl, IInterfaceIDoControl
{
}
Run Code Online (Sandbox Code Playgroud)

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

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

但是,如果我将"ClassIDoNotControl"移动到另一个程序集中,我就达不到我的预期.相反,我看到输出暗示额外堆栈帧的"MyCompany.IInterfaceIDoControl.SomeMethod".

原因是在C#编译器下,将"ClassIDoControl"更改为如下所示:

class ClassIDoControl : OtherCompany.ClassIDoNotControl, IInterfaceIDoControl
{
    void IInterfaceIDoControl.SomeMethod(string argument)
    {
        base.SomeMethod(argument);
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法避免这个编译器生成的额外的间接层与明确实现的接口?

Tim*_*mwi 43

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

答案很长:

  • 如果基类中的方法已经是虚拟的,则不需要额外的任何内容:接口方法可以绑定到它.

  • If the method in the base class is not virtual, but in the same assembly, the sneaky compiler actually makes it virtual and final. Reflector confirms this. ("final" is the CLR terminology for "sealed" in C#.)

  • If the method in the base class is not virtual and in another assembly, then obviously the compiler can’t do this because it can’t modify the already-compiled assembly. Therefore, the only option here is to insert a redirect method that implements the interface method. Like all methods that implement an interface method, it too is marked virtual and final.

So the answer to your last question, "Is there a way to avoid this?", is unfortunately no.