可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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
{
int I.M() { return 1; }
}
class B : A, I
{
int I.M() { return 2; }
}
From the derived class' implementation of I.M()
, I'd like to call the implementation of the base class, but I don't see how to do it. What I tried so far is this (in class B):
int I.M() { return (base as I).M() + 2; }
// this gives a compile-time error
//error CS0175: Use of keyword 'base' is not valid in this context
int I.M() { return ((this as A) as I).M() + 2; }
// this results in an endless loop, since it calls B's implementation
Is there a way to do this, without having to implement another (non interface-explicit) helper method?
Update:
I know it's possible with a "helper" method which can be called by the derived class, e.g:
class A : I
{
int I.M() { return M2(); }
protected int M2 { return 1; }
}
I can also change it to implement the interface non-explicitly. But I was just wondering if it's possible without any of these workarounds.
回答1:
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
...
回答2:
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.
回答3:
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.
回答4:
You can't call Explicit interface method in base class,here i solved this issue
I have two interface -> Interface1 and Interface2
public interface Interface1
{
string method2();
}
public interface Interface2
{
string method22();
}
Main class Method
class Program
{
static void Main(string[] args)
{
class1 cls = new class1();
string str = cls.method2();
}
}
and my interface implemented class
class class1 : Interface1, Interface2
{
#region Interface1 Members
public string method2()
{
return (this as Interface2).method22();
}
#endregion
#region Interface2 Members
string Interface2.method22()
{
return "2";
}
#endregion
}
回答5:
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();
}
}
}
回答6:
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);
}