在子类中覆盖接口的显式实现的正确方法是什么?
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();
}
}
以上是对语法的最佳猜测,但显然这是错误的。它会导致以下编译时错误:
`ChildTest.ITest.Speak()':虚拟或抽象成员不能 私人
ChildTest.ITest.Speak()': containing type does not implement interface
ITEST'
修饰符“覆盖”对此项无效
我实际上可以在不使用显式接口的情况下使用它,所以它实际上并没有阻止我,但我真的想知道,为了我自己的好奇心,如果想用显式接口做什么是正确的语法?< /强>
答案 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";
}
}