如何在基类上调用显式实现的接口方法

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...

  • 添加为什么不可能:明确实现的接口方法是私有的 - 使得无法从派生类调用它们.您应该更喜欢不同的方法,例如Daniel列出的方法,以避免*调用超级*代码气味. (4认同)

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)

是我灵感的源泉.

  • 仅仅因为你可以做某事并不意味着你必须这样做. (2认同)
  • 仅仅因为您可能应该考虑不做某事并不意味着没有实例是必不可少的;-) @Roland,感谢您的分享,可以为您服务! (2认同)