且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

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

更新时间:2023-02-14 15:30:36

实现一个接口方法必须是virtual( Ecma 335 Partition II Section 12.1)。



长回答: b


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

    li>
  • 如果基类中的方法是不是 virtual,但是在同一个程序集中,实际编译器实际上使它成为virtual和final 。反射器证实了这一点。 (final是C#中sealed的CLR术语。)


  • 方法在基类中不是虚拟的,在另一个程序集中,那么显然编译器不能这样做,因为它不能修改已经编译的程序集。因此,这里唯一的选择是插入一个实现接口方法的重定向方法。像实现接口方法的所有方法一样,它也被标记为 virtual和final




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


I ran into a strange C# edge case and am looking for a good work-around.

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. Instead, I see "MyCompany.IInterfaceIDoControl.SomeMethod" for the output implying an extra stack frame.

The reason is that under the covers, the C# compiler is changing "ClassIDoControl" to look like this:

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).

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. ("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.