I have a situation, where two classes (one deriving from the other) both implement the same interface explicitly:
interface I
{
int M();
}
class A : 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.
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
...
using System;
namespace SampleTest
{
interface IInterface1
{
void Run();
}
interface IInterface2
{
void Run();
}
public class BaseClass : IInterface1, IInterface2
{
public void Interface1Run()
{
(this as IInterface1).Run();
}
public void Interface2Run()
{
(this as IInterface2).Run();
}
void IInterface2.Run()
{
Console.WriteLine("I am from interface 2");
}
void IInterface1.Run()
{
Console.WriteLine("I am from interface 1");
}
}
public class ChildClass : BaseClass
{
public void ChildClassMethod()
{
Interface1Run();
Interface2Run();
}
}
public class Program : ChildClass
{
static void Main(string[] args)
{
ChildClass childclass = new ChildClass();
childclass.ChildClassMethod();
}
}
}
Here is my version of Roland Pihlakas's nice solution. This version supports the entire inheritance chain instead of immediate base class. The Invoke method includes additional parameters and there is a void type Invoke for non-function methods.
public class BaseClassExplicitInterfaceInvoker<T>
{
readonly Dictionary<string, MethodInfo> Cache = new Dictionary<string, MethodInfo>();
MethodInfo FindMethod(string MethodName)
{
if (Cache.TryGetValue(MethodName, out var Result)) return Result;
var BaseType = typeof(T);
while (Result == null)
{
if ((BaseType = BaseType.BaseType) == typeof(object)) break;
var Methods = BaseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
Result = Methods.FirstOrDefault(X => X.IsFinal && X.IsPrivate && (X.Name == MethodName || X.Name.EndsWith("." + MethodName)));
}
if (Result != null) Cache.Add(MethodName, Result);
return Result;
}
public void Invoke(T Object, string MethodName, params object[] Parameters) => FindMethod(MethodName).Invoke(Object, Parameters);
public ReturnType Invoke<ReturnType>(T Object, string MethodName, params object[] Parameters) => (ReturnType)FindMethod(MethodName).Invoke(Object, Parameters);
}
On option would be to create a base class that doesn't excplicitly implement an interface, and to only implement the interface on the subclass.
public class MyBase
{
public void MethodA()
{
//Do things
}
}
public interface IMyInterface
{
void MethodA();
void MethodB();
}
public class MySub: MyBase, IMyInterface
{
public void MethodB()
{
//Do things
}
}
Doing this will allow you to access the base classes MethodA without having to implemnet it in MySyb.
it is necessary explicitly?... Can you use an abstract class or class instead of interface?
interface ISample {}
class A : ISample {}
class B : A {}
...
base.fun();
...
http://msdn.microsoft.com/en-us/library/hfw7t1ce(v=vs.71).aspx
I have no idea its not possible call base method when it comes from implementation of interface.