#Google Analytic Tracker

Pages

Feb 18, 2010

C# Overriding Base Class Explicit Method

Recently one of my colleagues asked the team how to override a base class method that was declared as explicit. This is actually an interesting question. An there is a lengthy discussion on why you can’t override a explicit base class method from your derived class.

http://bytes.com/topic/c-sharp/answers/271737-how-can-i-call-base-interface-method

The first question is, can you call a base explicit method?

   1: using System;
   2: namespace CSharpCodeTest
   3: {
   4:     interface IFoo { void Foo(); }
   5:  
   6:     class A : IFoo
   7:     {
   8:         void IFoo.Foo()
   9:         {
  10:             Console.WriteLine("A.Foo runs");
  11:         }
  12:     }
  13:  
  14:     class B : A
  15:     {
  16:         public void MyFoo()
  17:         {
  18:             IFoo mySelf = this;
  19:             mySelf.Foo();
  20:         }
  21:     }
  22:  
  23:     class Program
  24:     {
  25:         static void Main(string[] args)
  26:         {
  27:             B b = new B();
  28:             b.MyFoo();
  29:         }
  30:     }
  31:  
  32: }

The compiler works, and I got my result. So, we are able to call our explicit base method through the use of “this”.

So, the next step is try to override B.Foo()

   1: using System;
   2: using NUnit.Framework;
   3:  
   4: namespace CSharpCodeTest
   5: {
   6:     interface IFoo
   7:     {
   8:         void Foo();
   9:     }
  10:  
  11:     class A : IFoo
  12:     {
  13:         void IFoo.Foo()
  14:         {
  15:             Console.WriteLine("A.Foo runs");
  16:         }
  17:     }
  18:  
  19:     class B : A, IFoo
  20:     {
  21:         void IFoo.Foo()
  22:         {
  23:             Console.WriteLine("B.Foo runs");
  24:         }
  25:     }
  26:  
  27:     [TestFixture]
  28:     public class TestCases
  29:     {
  30:         [Test]
  31:         public void Test1()
  32:         {
  33:             B b = new B();
  34:  
  35:             //Call by casting IFoo
  36:             ((IFoo)b).Foo();
  37:  
  38:             //Call by casting A, then by IFoo
  39:             A a = b;
  40:             ((IFoo) a).Foo();
  41:         }
  42:     }
  43:  
  44: }

This is the result

image

So, in this sense, polymorphism still works. That means I am allow to create my own Foo() in the derived class.

How about I try to call base.Foo(), in my override Foo() that is non-explicit?

   1: class A : IFoo
   2: {
   3:     void IFoo.Foo()
   4:     {
   5:         Console.WriteLine("A.Foo runs");
   6:     }
   7: }
   8:  
   9: class B : A
  10: {
  11:     public void Foo()
  12:     {
  13:         IFoo mySelf = this;
  14:         mySelf.Foo();
  15:     }
  16: }
  17:  
  18: class Program
  19: {
  20:     static void Main(string[] args)
  21:     {
  22:         B b = new B();
  23:         b.Foo();
  24:     }
  25: }

Hey, it works too, once I cast the “this” into IFoo, I can still access the base.Foo().

At last, what if I try to override this explicit Foo()? I changed the code from “public void” to “void IFoo.Foo”

   1: class B : A, IFoo
   2: {
   3:     void IFoo.Foo()
   4:     {
   5:         IFoo mySelf = this;
   6:         mySelf.Foo();
   7:     }
   8: }

Ouch, infinite loop. In fact, I have to explicit declare class B with IFoo in order for the compiler to work. Even if I try casting to A:

   1: class B : A, IFoo
   2: {
   3:     void IFoo.Foo()
   4:     {
   5:         //IFoo mySelf = this;
   6:         IFoo myself = (IFoo)(A)this;
   7:         myself.Foo();
   8:     }
   9: }
Nothing will work.
 
The reason is because class B can only have one IFoo implementation. When I explicitly declare B as IFoo, and implemented the IFoo.Foo(), class B no longer has the original class A.Foo().
 
AND… unfortunately there is no special syntax or format to tell the compiler to execute base.IFoo.Foo(), therefore there is no way to call the base.Foo().

I believe this is a missing feature in C#. If C# allows you to call base.Foo() through the IFoo(this).Foo(), you should allow to call it when overriding the method.

To hack around the problem, in the forum, one suggested to use reflection:

InterfaceMapping map = GetType().BaseType.GetInterfaceMap(typeof(IFoo));
map.TargetMethods[0].Invoke(this, new object[]{});

I would suggest try to create a wrapper class if possible, instead of create a derive class.

In fact, there is a FXCop rule on this issue: http://msdn.microsoft.com/en-us/library/ms182153%28VS.80%29.aspx

2 comments:

Anonymous said...

I would suggest you should override correctly, use the override keyword.

interface ITest
{
void Do();
}

class Test : ITest
{
protected virtual void Do()
{

}

void ITest.Do()
{
Do();
}
}

class Test2 : Test, ITest
{
protected override void Do()
{
base.Do();
}

void ITest.Do()
{
Do();
}
}

Adrian said...

Thank you for the useful post.