Justin Aquadro
Justin Aquadro

Reputation: 2310

Why doesn't C# support explicitly implemented virtual methods?

Interface methods in C# can be implemented explicitly, so that their implementation is invoked when an instance is explicitly cast to the interface type. Why is this not also supported on virtual methods of classes?

Although working around the 'multiple inheritance' issue is unique to interfaces, it seems that for every other reason that explicitly implemented members would be useful for interfaces, they would also be useful for virtual methods. A cleaner return-type covariance model springs to mind.

Edit: By request, an example:

public class Foo {
    ...
}

public class Bar : Foo {
   ...
}

class Base {
   abstract Foo A ();
}

class Dervied {
  private Bar _b;

  Bar A () {
    return _b;
  }

  Foo Base.A () {
    return _b;
  }
}

I am aware of using helper methods to simulate this, but the net effect seems to have any of the bad characteristics that explicit implementation would have, but with a dirtier API. The crux of my question is not how to do return type covariance, but why a similar mechanism for interfaces is not supported for virtual methods.

Upvotes: 3

Views: 1465

Answers (2)

CodesInChaos
CodesInChaos

Reputation: 108790

Some people recommend not having public virtual methods in the first place. But instead create one public non virtual method representing the consumer interface, and one protected virtual method representing the implementer interface.

I would not call separating the contracts for caller and implementer "muddying the design". In many cases it's cleaner IMO, but I'm usually too lazy to actually do it that way.

This design works much better with return type covariance and method hiding.

An additional benefit of this is that the public wrapper can add additional checking code and supports different contracts for the caller and implementer.

An example of how I'd emulate return type covariance:

public class Base
{
    protected virtual Base FooOverride(int i){return new Base();};//FooOverride does not need to duplicate the argument checking

    public Base Foo(int i)
    {
        if(i<0)
          throw new ArgumentException("i<0");
        return FooOverride(i);
    }
}

public class Derived:Base
{
    protected override Base FooOverride(int i){return new Derived();};
    public new Derived Foo(int i)
    {
        return (Derived)base.Foo();
    }
}

Upvotes: 5

Zack Elan
Zack Elan

Reputation: 1756

What benefit would that have, besides from allowing something like this?

class Base
{
    virtual void M() { }
}

class Derived : Base
{
    override void M() { }

    override void Base.M() { }
}

This effectively bakes a violation of the Liskov Substitution Principle into the C# language - if I have a variable of type Base, calling M() on it can do entirely different things depending on whether the run-time type is Base or Derived.

Explicit interface implementation is different. Say you have this:

interface IFoo
{
    void DoStuff();   
}

interface IBar
{
    void DoStuff();
}

class C : IFoo, IBar
{
    void IFoo.DoStuff() { }

    void IBar.DoStuff() { }
}

This preserves the LSP - if I have an IFoo variable that happens to be of run-time type C, calling DoStuff() on it will get the IFoo implementation of it. Likewise with IBar.

Upvotes: 3

Related Questions