简体   繁体   English

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

[英]Why does the C# compiler insert an explicit interface implementation?

I ran into a strange C# edge case and am looking for a good work-around. 我遇到了一个奇怪的C#边缘案例,我正在寻找一个好的解决方案。

There is a class that I do not control that looks like this: 有一个我无法控制的类看起来像这样:

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

I'd like to inherit from this class in a class I do control. 我想从这个类中的一类我控制继承。 Additionally, I'd like to specify an interface on it: 另外,我想在其上指定一个接口:

interface IInterfaceIDoControl
{
    void SomeMethod(string argument);
}

class ClassIDoControl : OtherCompany.ClassIDoNotControl, IInterfaceIDoControl
{
}

If all of these files are in the same assembly, everything works great: 如果所有这些文件都在同一个程序集中,那么一切都很好:

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

But, if I move "ClassIDoNotControl" into another assembly, I don't get what I expected. 但是,如果我将“ClassIDoNotControl”移动到另一个程序集中,我就达不到我的预期。 Instead, I see "MyCompany.IInterfaceIDoControl.SomeMethod" for the output implying an extra stack frame. 相反,我看到输出暗示额外堆栈帧的“MyCompany.IInterfaceIDoControl.SomeMethod”。

The reason is that under the covers, the C# compiler is changing "ClassIDoControl" to look like this: 原因是在C#编译器下,将“ClassIDoControl”更改为如下所示:

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

Is there a way to avoid this compiler-generated extra layer of indirection with explicitly implemented interfaces? 有没有办法避免这个编译器生成的额外的间接层与明确实现的接口?

Short answer: The CLR requires that all methods that implement an interface method must be virtual ( Ecma 335 Partition II Section 12.1). 简短回答: CLR要求实现接口方法的所有方法都必须是虚拟的( Ecma 335 Partition II Section 12.1)。

Long answer: 答案很长:

  • If the method in the base class is already virtual, then nothing extra is needed: the interface method can be bound to it. 如果基类中的方法已经是虚拟的,则不需要额外的任何内容:接口方法可以绑定到它。

  • 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. Reflector证实了这一点。 (“final” is the CLR terminology for “sealed” in C#.) (“final”是C#中“密封”的CLR术语。)

  • 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. 所以你最后一个问题的答案是“有没有办法避免这种情况?”,遗憾的是没有。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM