覆盖显式接口实现?

时间:2016-05-18 22:07:50

标签: c# oop syntax interface

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

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();
    }
}

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

错误CS0621:

  

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

错误CS0540:

  

ChildTest.ITest.Speak()': containing type does not implement interface ITEST'

错误CS0106:

  

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

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

5 个答案:

答案 0 :(得分:8)

显式接口实现不能是虚拟成员。请参阅C# language specification的第13.4.1节(它已过时但在C#6.0中似乎没有更改此逻辑)。具体做法是:

  

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

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

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

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

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

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

答案 1 :(得分:3)

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

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

public class ChildTest : ParentTest, ITest
{
  string ITest.Speak()
  {
    return "Mooo";
  }
  // Note: any other interface functions will call ParentTest's implementation
}

然而,现在没有&#34;合法的&#34;在类型为ParentTest的对象上调用ITest.Speak ChildTest的实现方式,因为任何使用该界面的尝试都会导致ChildTest&#39}改为调用实现。

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

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

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();
  }
}

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

答案 2 :(得分:1)

您可以使用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";
    }
}

答案 3 :(得分:0)

父母中的

public virtual string Speak()和孩子中的public override string Speak()应该可以正常工作。您不能为此用例使用显式接口。您可以通过声明受保护的成员并在显式接口实现中调用它来解决它。如果您需要使用它们。

答案 4 :(得分:0)

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

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";
    }
}