Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why to Use Explicit Interface Implementation To Invoke a Protected Method?

When browsing ASP.NET MVC source code in codeplex, I found it is common to have a class explicitly implementing interface. The explicitly implemented method/property then invoke another "protected virtual" method/property with same name.

For example,

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

    bool IHttpHandler.IsReusable 
    {
        get 
        {
           return IsReusable;
        }
    }
}

I'm now sure what's the benefit of this kind of programming. For me, I prefer to just implicitly implement the interface IHttpHandler.

I guess the author just don't want MvcHandler has a public property IsResuable. The property IsReusable can only be used when instance of MvcHandler is treated as a IHttpHandler. Still, I'm not sure why the author what this way.

Anybody know more benefits about this style of interface implementation?

like image 956
Morgan Cheng Avatar asked Nov 11 '08 10:11

Morgan Cheng


People also ask

What is implicit and explicit interface implementation in C#?

An implicit interface implementation is where you have a method with the same signature of the interface. An explicit interface implementation is where you explicitly declare which interface the method belongs to.

What is implicit interface?

With implicit interface implementations, the members of the interface are public in the class. With explicit implementations, in the class the interface members are not declared as public members and cannot be directly accessed using an instance of the class, but a cast to the interface allows accessing the members.


3 Answers

Well, not specific to MVC, but this approach allows you to keep the core public API clean. It is also useful if there is ever a risk of different interfaces / etc having the same name & signature, but different meaning. In reality this is rare.

It also allows you to provide an implementation where you want the return type to change in subclasses:

(ICloneable chosen for simplicity - don't get hung up on the fact that it is a poorly defined interface... a better example would have been things like DbCommand etc, which do this - but that is harder to show in a short example)

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

If we had used a public virtual method, we wouldn't be able to override it and use new in the base-class, as you aren't allowed to do both:

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() { ... }
}

Using the protected virtual approach, any usage:

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

all use the correct CloneCore() implementation for the concrete type.

like image 116
Marc Gravell Avatar answered Nov 15 '22 19:11

Marc Gravell


If a class implements IFoo.Bar explicitly, and a derived class needs IFoo.Bar to do something different, there will be no way for the derived class to call the base-class implementation of that method. A derived class which does not re-implement IFoo.Bar could call the base-class implementation via ((IFoo)this).Bar(), but if the derived class re-implements IFoo.Bar (as it would have to in order to change its behavior) the aforementioned call would go to the derived-class re-implementation, rather than the base-class implementation. Even ((IFoo)(BaseType)this).bar wouldn't help, since casting a reference to an interface type will discard any information about the type of the reference (as opposed to the type of the instance instance) that was cast.

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.

like image 32
supercat Avatar answered Nov 15 '22 20:11

supercat


  1. When a member is explicitly implemented, it cannot be accessed through a class instance, but only through an instance of the interface. reference : Explicit Interface Implementation Tutorial
  2. As my experience if interface implementer explicitly implement an interface he will receive compiler error after you drop a method from interface while he will not notify if he/she implicitly implement it and the method will remain in the code.

sample for reason 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
    }
}
like image 21
Mohammad Nikravan Avatar answered Nov 15 '22 21:11

Mohammad Nikravan