GazTheDestroyer
GazTheDestroyer

Reputation: 21241

virtual calls on overridden interface implementations

If I have two classes that both implement an interface, but also inherit, do I need to make the function virtual? eg given:

interface IDoSomething
{
    void DoSomething();
}

class A : IDoSomething
{
    public void DoSomething()
    {
        //do A
    }
}

class B : A
{
    public new void DoSomething()
    {
        //do B
    }
}

Would the following code do A or B?

IDoSomething doer = new B();
doer.DoSomething(); //do A or do B?

I'm getting confused because I'm under the impression that all inteface calls are effectively virtual, but obviously I am using the new operator to hide the base definition.

Upvotes: 0

Views: 429

Answers (4)

supercat
supercat

Reputation: 81115

Although C# and .net allow derived classes to re-implement interface methods, it is often better to have the base class use a virtual method to implement the interface, and have the derived class override that method, in any situation where a derived class might wish to augment, rather than entirely replace, the base-class implementation. In some languages like vb.net, this can be done directly regardless of whether a class exposes a public member with the same name and signature as the interface member being implemented. In other languages like C#, a public method which implements an interface can be marked unsealed and virtual (allowing a derived class to override it and have that override call base.Member(params) but an explicit interface implementation cannot. In such languages, the best one can do is something like:

class MyClass : MyInterface
{
  void MyInterface.DoSomething(int param)
  {
    doSomething(param);
  }
  protected virtual void doSomething(int param)
  {
    ...
  }
}
class MyClass2 : MyClass
{
  protected override void doSomething(int param)
  {
    ...
    base.doSomething(param);
    ...
  }
}

In some cases, having the interface implementation wrap a virtual call can be advantageous, since it allows the base class to ensure that certain things happen before or after the overridden function. For example, a non-virtual interface implementation of Dispose could wrap a virtual Dispose method:

  int DisposingFlag; // System.Boolean doesn't work with Interlocked.Exchange
  void IDisposable.Dispose()
  {
    if (Threading.Interlocked.CompareExchange(DisposingFlag, 1, 0) == 0)
    {
      Dispose(true);
      DisposingFlag = 2;
      Threading.Thread.MemoryBarrier();
      GC.SuppressFinalize(this);
    }
  }
  public bool Disposed { get {return (DisposingFlag != 0);} }
  public bool FullyDisposed { get {return (DisposingFlag > 1);} }

This will (unlike Microsoft's default wrapper) ensure that Dispose only gets called once, even if multiple threads try to call it simultaneously. Further, it makes a Disposed property available. Using Microsoft's wrapper, every derived class that wants a Disposed flag would have to define its own; even if the base-class Disposed flag were protected or public, it wouldn't be safe to use because it wouldn't get set until after derived classes had already begun cleanup. Setting DisposingFlag within the wrapper avoids that problem.

Upvotes: 0

Tim S.
Tim S.

Reputation: 56536

I prefer leppie's solution. If that's not an option:

class A : IDoSomething
{
    void IDoSomething.DoSomething()
    {
        //do A
    }
}

class B : A
{
    void IDoSomething.DoSomething()
    {
        //do B
    }
}

But note that this will hide the implementation, so you can't do ((A)doer).DoSomething().

If you can't change class A to either of these solutions, I don't think there's a sure way to override it in all cases. You could both explicitly implement the interface and make a public new method on B. That way if it's statically known as an IDoSomething or as a B it will use B's implementation, but if it's known as an A it will still use A's implementation.

Upvotes: 0

Ebad Masood
Ebad Masood

Reputation: 2379

Here is the explanation. Already available at stackoverflow forums.

Quoting Jeffrey Ritcher from CLR via CSharp 3rd Edition here

The CLR requires that interface methods be marked as virtual. If you do not explicitly mark the method as virtual in your source code, the compiler marks the method as virtual and sealed; this prevents a derived class from overriding the interface method. If you explicitly mark the method as virtual, the compiler marks the method as virtual (and leaves it unsealed); this allows a derived class to override the interface method. If an interface method is sealed, a derived class cannot override the method. However, a derived class can re-inherit the same interface and can provide its own implementation for the interface’s methods.

Upvotes: 4

leppie
leppie

Reputation: 117220

class A : IDoSomething
{
    public virtual void DoSomething()
    {
        //do A
    }
}

class B : A
{
    public override void DoSomething()
    {
        //do B
    }
}

Upvotes: 2

Related Questions