为什么使用显式接口实现来调用受保护的方法?

在codeplex中浏览ASP.NET MVC源代码时,我发现有一个类显式实现接口是很常见的。 显式实现的方法/属性然后调用具有相同名称的另一个“受保护的虚拟”方法/属性。

例如,

public class MvcHandler : IHttpHandler, IRequiresSessionState { protected virtual bool IsReusable { get { return false; } } bool IHttpHandler.IsReusable { get { return IsReusable; } } } 

我现在确定这种编程的好处是什么。 对我来说,我更喜欢隐式实现接口IHttpHandler。

我猜作者只是不希望MvcHandler有一个公共属性IsResuable 。 仅当MvcHandler的实例被视为IHttpHandler时,才能使用属性IsReusable 。 不过,我不确定为什么作者这样做。

有人知道这种界面实现的更多好处吗?

好吧,不是特定于MVC,但这种方法允许您保持核心公共API干净 。 如果存在具有相同名称和签名但具有不同含义的不同接口/等的风险,则它也是有用的。 实际上这很少见。

它还允许您提供希望在子类中更改返回类型的实现:

(为了简单起见选择了ICloneable – 不要因为它是一个定义不明确的接口而被挂起……更好的例子就是像DbCommand东西,这样做 – 但是在一个简短的例子中更难以显示)

 class Foo : ICloneable { public Foo Clone() { return CloneCore(); } object ICloneable.Clone() { return CloneCore(); } protected virtual Foo CloneCore() { ... } } class Bar : Foo { protected override Foo CloneCore() { ... } public new Bar Clone() { return (Bar)CloneCore(); } } 

如果我们使用了公共虚方法,我们将无法override在基类中使用new ,因为您不允许同时执行这两个操作:

 class A { public virtual A SomeMethod() { ... } } class B : A { public override A SomeMethod() { ... } //Error 1 Type 'B' already defines a member called 'SomeMethod' with the same parameter types public new B SomeMethod() { ... } } 

使用受保护的虚拟方法,任何用法:

  • Foo.Clone()
  • Bar.Clone()
  • ICloneable.Clone()

所有对具体类型使用正确的CloneCore()实现。

如果一个类显式地实现了IFoo.Bar ,并且一个派生类需要IFoo.Bar来做一些不同的事情,那么派生类就没有办法调用该方法的基类实现。 不重新实现IFoo.Bar的派生类可以通过((IFoo)this).Bar()调用基类实现((IFoo)this).Bar() ,但是如果派生类重新实现IFoo.Bar (因为它必须按顺序改变它的行为)前面提到的调用将转到派生类重新实现,而不是基类实现。 Even ((IFoo)(BaseType)this).bar无济于事,因为转换对接口类型的引用将丢弃有关转换类型(与实例实例的类型相对)的任何信息。

具有显式接口实现除了调用受保护方法之外什么都不做,可以避免此问题,因为派生类可以通过覆盖虚方法来更改接口方法的行为,同时保留在其认为合适时调用基本实现的能力。 恕我直言,C#应该有一个显式的接口实现产生一个具有CLS兼容名称的虚方法,所以有人用C#编写一个显式实现IFoo.Bar的类的衍生物可以说override void IFoo.Bar ,有人写一些其他语言可以说,例如Overrides Sub Explicit_IFoo_Bar() ; 因为任何派生类都可以重新实现IFoo.Bar ,并且因为任何不重新实现IFoo.Bar派生类都可以自己调用它,所以我没有看到将显式实现密封的任何有用的目的。

顺便提一下,在vb.net中,普通模式只是Protected Overridable Sub IFoo_Bar() Implements IFoo.Bar ,而不需要单独的虚方法。

  1. 当显式实现成员时,不能通过类实例访问它,而只能通过接口的实例访问它。 参考: 显式接口实现教程
  2. 根据我的经验,如果接口实现者明确地实现了接口,那么在从接口删除方法后他将收到编译器错误,而如果他/她隐式实现它并且该方法将保留在代码中,则他将不会通知。

样本1:

 public interface IFoo { void method1(); void method2(); } public class Foo : IFoo { // you can't declare explicit implemented method as public void IFoo.method1() { } public void method2() { } private void test() { var foo = new Foo(); foo.method1(); //ERROR: not accessible because foo is object instance method1(); //ERROR: not accessible because foo is object instance foo.method2(); //OK method2(); //OK IFoo ifoo = new Foo(); ifoo.method1(); //OK, because ifoo declared as interface ifoo.method2(); //OK } }