Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding explicit interface implementations?

What is the proper way to override explicit implementations of an interface in a child class?

public interface ITest
{
    string Speak();
}

public class ParentTest : ITest
{
    string ITest.Speak()
    {
        return "Meow";
    }
}

public class ChildTest : ParentTest
{
    // causes compile time errors
    override string ITest.Speak()
    {
        // Note: I'd also like to be able to call the base implementation
        return "Mooo" + base.Speak();
    }
}

The above is a best guess for the syntax, but obviously it's wrong. It causes the following compile time errors:

error CS0621:

`ChildTest.ITest.Speak()': virtual or abstract members cannot be private

error CS0540:

ChildTest.ITest.Speak()': containing type does not implement interfaceITest'

error CS0106:

The modifier `override' is not valid for this item

I can actually get this to work without using explicit interfaces so it's not actually blocking me but I would really like know, for my own curiosity, what is the correct syntax if wanted to do this with explicit interfaces?

like image 796
James McMahon Avatar asked May 18 '16 22:05

James McMahon


3 Answers

An explicit interface implementation cannot be a virtual member. See section 13.4.1 of the C# language specification (it is outdated but this logic does not appear to have changed in C# 6.0). Specifically:

It is a compile-time error for an explicit interface member implementation to include access modifiers, and it is a compile-time error to include the modifiers abstract, virtual, override, or static.

This means, you will never be able to directly override this member.

What you can do as a workaround is to call another virtual method from your explicit implementation:

class Base : IBla
{
    void IBla.DoSomething()
    {
        this.DoSomethingForIBla();
    }

    protected virtual void DoSomethingForIBla()
    {
        ...
    }
}

class Derived : Base
{
    protected override void DoSomethingForIBla()
    {
        ...
    }
}
like image 101
Bas Avatar answered Oct 22 '22 03:10

Bas


I also had a situation where I thought I wanted to override an explicit interface implementation and call the base class and found this question with its answers saying "can't be done".

The first thing to note is that in order to override the explicit interface implementation WITHOUT calling the base class is fairly simple. The derived class merely needs to implement the interface itself.

public class ChildTest : ParentTest, ITest
{
  string ITest.Speak()
  {
    return "Mooo";
  }
  // Note: any other interface functions will call ParentTest's implementation
}

However, there is now no "legitimate" way to call ParentTest's implementation of ITest.Speak on an object of type ChildTest, as any attempt to use the interface will result in ChildTest's implementation being called instead.

Thus, it is only the call to the base implementation that causes complication. To satisfy my curiosity, I proved that it CAN be done, but really it shouldn't...

Leaving the base class unchanged, the following does in fact allow the base class to be called using reflection.

public class ChildTest : ParentTest, ITest
{
  string ITest.Speak()
  {
    return "Mooo" + typeof(ParentTest).GetMethod("ITest.Speak", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(this, new object[0]) as string;
  }
}

NB if the sample code is enclosed in a namespace, the fully qualified interface name is required. e.g. "MyNamespace.ITest.Speak"

If the function will be called repeatedly and/or for many objects, performance can be improved by caching the method info, and/or creating a delegate for the base call, e.g.:

public class ChildTest : ParentTest, ITest
{
  static ChildTest()
  {
    baseSpeakMethodInfo = typeof(ParentTest).GetMethod("ITest.Speak", BindingFlags.Instance | BindingFlags.NonPublic);
  }

  static private MethodInfo baseSpeakMethodInfo;

  public ChildTest()
  {
    baseSpeak = baseSpeakMethodInfo.CreateDelegate(typeof(Func<string>), this) as Func<string>;
  }

  private Func<string> baseSpeak;

  string ITest.Speak()
  {
    return "Mooo" + baseSpeak();
  }
}

The only advantage this has over other answers is that it works if you cannot modify the base class. Otherwise, it's a horrible solution, and a mechanism should be created in the base class (as in other answers) to provide the derived class with a legitimate way to call the base implementation.

like image 36
Steve Avatar answered Oct 22 '22 03:10

Steve


You can use a protected virtual method, and keep the implementation non-public, so you still have explicit interface implementation which is just a wrapper around the implementation:

public class ParentTest : ITest
{
    protected virtual string Speak_Impl()
    {
        return "Meow";
    }
    string ITest.Speak()
    {
        return Speak_Impl();
    }
}

public class ChildTest : ParentTest
{
    protected override string Speak_Impl()
    {
        return "Mooo";
    }
}
like image 28
Joe Enos Avatar answered Oct 22 '22 04:10

Joe Enos