覆盖显式接口实现?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了覆盖显式接口实现?相关的知识,希望对你有一定的参考价值。

覆盖子类中接口的显式实现的正确方法是什么?

public interface ITest
{
    string Speak();
}

public class ParentTest : ITest
{
    string ITest.Speak()
    {
        return "Meow";
    }
}

public class ChildTest : ParentTest
{
    // causes compile time errors
    override string ITest.Speak()
    {
        // Note: I'd also like to be able to call the base implementation
        return "Mooo" + base.Speak();
    }
}

以上是对语法的最佳猜测,但显然这是错误的。它会导致以下编译时错误:

error CS0621:

`ChildTest.ITest.Speak()':虚拟或抽象成员不能是私有的

error CS0540:

kazxsopoiITest“

error CS0106:

修饰符“覆盖”对此项无效

我实际上可以在不使用显式接口的情况下使用它,所以它实际上并没有阻止我,但我真的想知道,为了我自己的好奇心,如果想用显式接口做这个,那么正确的语法是什么?

答案

显式接口实现不能是虚拟成员。请参阅ChildTest.ITest.Speak()': containing type does not implement interface的第13.4.1节(它已过时,但在C#6.0中这个逻辑似乎没有改变)。特别:

显式接口成员实现包含访问修饰符是编译时错误,包含修饰符abstract,virtual,override或static是编译时错误。

这意味着,您永远无法直接覆盖此成员。

您可以做的解决方法是从显式实现中调用另一个虚方法:

C# language specification
另一答案

我还有一种情况,我认为我想覆盖一个显式的接口实现并调用基类,并发现这个问题的答案说“无法完成”。

首先要注意的是,为了覆盖显式接口实现而不调用基类非常简单。派生类只需要实现接口本身。

class Base : IBla
{
    void IBla.DoSomething()
    {
        this.DoSomethingForIBla();
    }

    protected virtual void DoSomethingForIBla()
    {
        ...
    }
}

class Derived : Base
{
    protected override void DoSomethingForIBla()
    {
        ...
    }
}

但是,现在没有“合法”的方法来调用public class ChildTest : ParentTest, ITest { string ITest.Speak() { return "Mooo"; } // Note: any other interface functions will call ParentTest's implementation } ParentTest类型的对象上实现ITest.Speak,因为任何使用该接口的尝试都会导致调用ChildTest的实现。

因此,只有对基本实现的调用才会导致复杂化。为了满足我的好奇心,我证明了它可以做到,但实际上它不应该......

保持基类不变,以下实际上允许使用反射调用基类。

ChildTest

注意如果示例代码包含在命名空间中,则需要完全限定的接口名称。例如public class ChildTest : ParentTest, ITest { string ITest.Speak() { return "Mooo" + typeof(ParentTest).GetMethod("ITest.Speak", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(this, new object[0]) as string; } }

如果将重复调用该函数和/或对于许多对象,则可以通过缓存方法信息和/或为基本调用创建委托来提高性能,例如:

"MyNamespace.ITest.Speak"

与其他答案相比,它的唯一优势是,如果您无法修改基类,它就有效。否则,这是一个可怕的解决方案,应该在基类中创建一个机制(如在其他答案中),以便为派生类提供调用基本实现的合法方法。

另一答案

您可以使用public class ChildTest : ParentTest, ITest { static ChildTest() { baseSpeakMethodInfo = typeof(ParentTest).GetMethod("ITest.Speak", BindingFlags.Instance | BindingFlags.NonPublic); } static private MethodInfo baseSpeakMethodInfo; public ChildTest() { baseSpeak = baseSpeakMethodInfo.CreateDelegate(typeof(Func<string>), this) as Func<string>; } private Func<string> baseSpeak; string ITest.Speak() { return "Mooo" + baseSpeak(); } } 方法,并将实现保持为非公共,因此您仍然具有显式接口实现,这只是实现的包装:

protected virtual
另一答案

您无法覆盖显式接口实现。它们不能是虚拟的,因此无法直接覆盖它们。但是,您可以通过调用受保护的虚拟成员来间接地使它们成为虚拟成员:

public class ParentTest : ITest
{
    protected virtual string Speak_Impl()
    {
        return "Meow";
    }
    string ITest.Speak()
    {
        return Speak_Impl();
    }
}

public class ChildTest : ParentTest
{
    protected override string Speak_Impl()
    {
        return "Mooo";
    }
}
另一答案

父母的public interface ITest { string Speak(); } public class ParentTest : ITest { string ITest.Speak() { return Speak(); } protected virtual string Speak() { return "Meow"; } } public class ChildTest : ParentTest { protected override string Speak() { return "Mooo"; } } 和孩子的public virtual string Speak()应该可以正常工作。您不能为此用例使用显式接口。您可以通过声明受保护的成员并在显式接口实现中调用它来解决它,如果您需要使用它们。

以上是关于覆盖显式接口实现?的主要内容,如果未能解决你的问题,请参考以下文章

在 Java 中显式调用默认方法

在 C# 中实现接口与显式实现接口 [重复]

如何使用接口在片段和活动之间进行通信?

C# 中的抽象显式接口实现

显式实现接口的 ReSharper 文件布局

为啥接口的显式实现不能公开?