10

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。属性IsReusable只能在MvcHandler的实例被视为IHttpHandler时使用。不过,我不确定作者为什么会这样。

有人知道这种接口实现方式的更多好处吗?

4

3 回答 3

14

好吧,不是特定于 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(); }
}

如果我们使用了公共虚拟方法,我们将无法使用overridenew在基类中使用,因为您不能同时这样做:

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()实现。

于 2008-11-11T10:17:41.177 回答
2

如果一个类IFoo.Bar显式实现,而派生类需要IFoo.Bar做一些不同的事情,那么派生类将无法调用该方法的基类实现。不重新实现的派生类IFoo.Bar可以通过 调用基类实现((IFoo)this).Bar(),但是如果派生类重新实现IFoo.Bar(因为它必须为了改变其行为),上述调用将转到派生类 re -实现,而不是基类实现。即使((IFoo)(BaseType)this).bar没有帮助,因为将引用转换为接口类型将丢弃有关被转换的引用类型(与实例实例的类型相反)的任何信息。

Having an explicit interface implementation do nothing but call a protected method avoids this problem, since a derived class can change the behavior of the interface method by overriding the virtual method, while retaining the ability to call the base implementation as it sees fit. IMHO, C# should have had an explicit interface implementation produce a virtual method with a CLS-compliant name, so someone writing in C# a derivative of a class that explicitly implemented IFoo.Bar could say override void IFoo.Bar, and someone writing in some other language could say, e.g. Overrides Sub Explicit_IFoo_Bar(); since any derived class can re-implement IFoo.Bar, and since any derived class which doesn't re-implement IFoo.Bar can call it on itself, I don't see that there's any useful purpose to having the explicit implementation be sealed.

Incidentally, in vb.net, the normal pattern would simply be Protected Overridable Sub IFoo_Bar() Implements IFoo.Bar, without need for a separate virtual method.

于 2013-01-06T18:55:22.880 回答
1
  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
    }
}
于 2012-08-23T16:40:20.393 回答