M4N*_*M4N 29 c# interface base-class explicit-implementation
我有一种情况,其中两个类(一个派生自另一个)都明确地实现了相同的接口:
interface I
{
int M();
}
class A : I
{
int I.M() { return 1; }
}
class B : A, I
{
int I.M() { return 2; }
}
Run Code Online (Sandbox Code Playgroud)
从派生类的实现I.M(),我想调用基类的实现,但我不知道如何做到这一点.到目前为止我尝试的是(在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
Run Code Online (Sandbox Code Playgroud)
有没有办法做到这一点,而不必实现另一个(非接口显式)辅助方法?
更新:
我知道可以使用派生类调用的"辅助"方法,例如:
class A : I
{
int I.M() { return M2(); }
protected int M2 { return 1; }
}
Run Code Online (Sandbox Code Playgroud)
我也可以更改它以非显式地实现接口.但我只是想知道是否有可能没有任何这些变通方法.
Dan*_*rth 21
不幸的是,这是不可能的.
甚至没有辅助方法.辅助方法与第二次尝试具有相同的问题:this类型B,即使在基类中也会调用Min 的实现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(); }
}
Run Code Online (Sandbox Code Playgroud)
唯一的解决方法A是使用辅助方法,用于以下方法A的实现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(); }
}
Run Code Online (Sandbox Code Playgroud)
但你需要提供这样的方法,B如果有class C : B, I...
Rol*_*kas 10
可以使用反射.
代码如下.我添加了缓存作为基本优化,但可以通过使用Delegate.CreateDelegateon 进一步优化methodInfo.此外,可以使用添加参数计数和类型检查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>
Run Code Online (Sandbox Code Playgroud)
这是我灵感的源泉.