Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you call an explicitly declared interface member in a base class from a subclass?

Say you have access to a base class 'MyClass' that implements 'IFoo'. 'IFoo' defines the function 'int FooValue()' and 'MyClass' implements it explicitly. Now say you have a subclass of 'MyClass' called 'MySubClass' and you want to override 'FooValue' in that subclass, but you also want the subclass's implementation to be based on the result from the base class's implementation.

Now normally, this would be solved by simply moving the implementation to a protected function in the base class which we'd then simply overide in the subclass. Done and done. But we don't have access to the source code of the base class. We only have it as a reference to a library. So how do you solve this?

Not a Duplicate (update: ...as this one)!

There's this SO question here... C#: Property overriding by specifying the interface explicitly... that shows while you can't override a base class's interface through the normal channels per se, you can explicitly re-implement the same interface on a subclass and that behaves like you're overriding the interface (but in actuality you're re-implementing it, not overriding it.) That said, what I'm trying to figure out is how do I get at the base class's implementation. (That's why IMHO this isn't a duplicate of that question.)

Here's some pseudocode of the base class which again, we don't have access to code-wise...

public interface IFoo
{
    int FooValue();
}

public class MyClass : IFoo
{
    int IFoo.FooValue() <-- Explicit implementation requiring a cast to access.
    {
        return 4;
    }
}

This is what we're trying to do, but obviously this isn't allowed because you can't use 'base' like this.

public class MySubClass : MyClass
{
    int IFoo.FooValue()
    {
        int baseResult = ((IFoo)base).FooValue(); <-- Can't use 'base' like this
        return baseResult * 2;
    }
}

So is this possible?

like image 455
Mark A. Donohoe Avatar asked Jul 25 '13 05:07

Mark A. Donohoe


Video Answer


1 Answers

I will be honest, there is no straightforward answer to this. Feels like a limitation of the language. May be there is some sound reason for the lack of it.

However, I can think of some not so clean work arounds.

  1. Reflection. Imho, the simplest option here. One of those rare cases where reflection is really needed.

  2. Your own interface and base class derived from referenced library.

    //your interface
    public interface IRealFoo : IFoo
    {
        new int FooValue();
    }
    
    //your base class
    public class MyRealClass : MyClass, IRealFoo
    {
        protected virtual int FooValue()
        {
            return ((IFoo)this).FooValue();
        }
    
        int IRealFoo.FooValue()
        {
            return FooValue();
        }
    }
    
    //your child class
    public class MyRealSubClass : MyRealClass
    {
        protected override int FooValue()
        {
            return base.FooValue() * 2;
        }
    }
    

    And you deal with IRealFoo, MyRealClass and so on instead of IFoo, MyClass etc.

    IRealFoo x = new MyRealClass();
    IRealFoo y = new MyRealSubClass();
    Console.WriteLine(x.FooValue()); //4
    Console.WriteLine(y.FooValue()); //8
    
  3. Same as above but abstract class instead of interface.

    Same as above, but you can also have an abstract base class RealFoo instead of interface IFoo. This I think is slightly easier code, but need not be good code. It completely changes the intent of the code.

    public abstract class RealFoo : MyClass
    {
        public virtual int FooValue()
        {
            return ((IFoo)this).FooValue();
        }
    }
    
    public class MyRealClass : RealFoo 
    {
        public override int FooValue() 
        {
            return base.FooValue();
        }
    }
    
    public class MyRealSubClass : MyRealClass 
    {
        public override int FooValue() 
        {
            return base.FooValue() * 2;
        }
    }
    
    //call it like:
    RealFoo x = new MyRealClass();
    RealFoo y = new MyRealSubClass();
    Console.WriteLine(x.FooValue()); //4
    Console.WriteLine(y.FooValue()); //8
    
  4. Extension method along with dynamic.

    public class MyRealClass : MyClass 
    {
        public virtual int FooValue() 
        {
            return ((IFoo)this).FooValue();
        }
    }
    
    public class MyRealSubClass : MyRealClass 
    {
        public override int FooValue() 
        {
            return base.FooValue() * 2;
        }
    }
    
    public static int RealFooValue(this IFoo foo) 
    {
        return ((dynamic)foo).FooValue();
    }
    

    In this one case you can stick with familiar IFoo interface, but you got to call the extension method RealFooValue instead of FooValue. This will be confusing with potentially wrong result when calling FooValue. I dont advise it.

    IFoo x = new MyRealClass();
    IFoo y = new MyRealSubClass();
    Console.WriteLine(x.RealFooValue()); //4
    Console.WriteLine(y.RealFooValue()); //8
    
  5. Switch on type with if-else logic.

    public class MySubClass : MyClass
    {
    
    }
    
    public static int RealFooValue(this IFoo foo) 
    {
        var type = foo.GetType();
    
        if (type == typeof(MyClass))
            return foo.FooValue();
        else if (type == typeof(MySubClass))
            return foo.FooValue() * 2; //logic goes here
    
        throw new Exception();
    }
    

    This has the same problem as above. Dont recommend it.

    IFoo x = new MyClass();
    IFoo y = new MySubClass();
    Console.WriteLine(x.RealFooValue()); //4
    Console.WriteLine(y.RealFooValue()); //8
    
like image 101
nawfal Avatar answered Nov 14 '22 23:11

nawfal