How to call an explicitly implemented interface-method on the base class
Unfortunately, it isn't possible.
Not even with a helper method. The helper method has the same problems as your second attempt: this
is of type B
, even in the base class and will call the implementation of M
in B
:
interface I
{
int M();
}
class A : I
{
int I.M() { return 1; }
protected int CallM() { return (this as I).M(); }
}
class B : A, I
{
int I.M() { return CallM(); }
}
The only workaround would be a helper method in A
that is used in A
's implementation of M
:
interface I
{
int M();
}
class A : I
{
int I.M() { return CallM(); }
protected int CallM() { return 1; }
}
class B : A, I
{
int I.M() { return CallM(); }
}
But you would need to provide a method like this also for B
if there will be a class C : B, I
...
It is possible using reflection.
The code follows. I added caching as a basic optimization, but it can be optimized further by using Delegate.CreateDelegate
on methodInfo
. Also, parameter count and type checks can be added using methodInfo.GetParameters()
.
interface I
{
int M();
}
class A : I
{
int I.M() { return 1; }
}
class B : A, I
{
BaseClassExplicitInterfaceInvoker<B> invoker = new BaseClassExplicitInterfaceInvoker<B>();
int I.M() { return invoker.Invoke<int>(this, "M") + 2; }
}
public class BaseClassExplicitInterfaceInvoker<T>
{
private Dictionary<string, MethodInfo> cache = new Dictionary<string, MethodInfo>();
private Type baseType = typeof(T).BaseType;
private MethodInfo FindMethod(string methodName)
{
MethodInfo method = null;
if (!cache.TryGetValue(methodName, out method))
{
var methods = baseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
foreach (var methodInfo in methods)
{
if (methodInfo.IsFinal && methodInfo.IsPrivate) //explicit interface implementation
{
if (methodInfo.Name == methodName || methodInfo.Name.EndsWith("." + methodName))
{
method = methodInfo;
break;
}
}
}
cache.Add(methodName, method);
}
return method;
}
public RT Invoke<RT>(T obj, string methodName)
{
MethodInfo method = FindMethod(methodName);
return (RT)method.Invoke(obj, null);
}
} //public static class BaseClassExplicitInterfaceInvoker<T>
Here is the source of my inspiration.