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

时间:2011-05-12 09:50:33

标签: 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; }
}

从派生类'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

有没有办法做到这一点,而不必实现另一个(非接口显式)辅助方法?


更新

我知道可以使用派生类调用的“帮助器”方法,例如:

class A : I
{
    int I.M() { return M2(); }
    protected int M2 { return 1; }
}

我也可以更改它以非显式地实现接口。但我只是想知道是否有可能没有任何这些解决方法。

7 个答案:

答案 0 :(得分:20)

不幸的是,这是不可能的。
甚至没有辅助方法。辅助方法与第二次尝试具有相同的问题:this类型为B,即使在基类中也会调用M中的B实现:< / p>

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(); }
}

唯一的解决方法是在A的{​​{1}}实施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(); } } ......

,您还需要为B提供这样的方法

答案 1 :(得分:10)

可以使用反射。
代码如下。我将缓存添加为基本优化,但可以使用Delegate.CreateDelegate上的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>

Here是我灵感的源泉。

答案 2 :(得分:0)

有必要明确吗?...你能使用抽象类或类而不是接口吗?

interface ISample {}
class A : ISample {}
class B : A {}
...
base.fun();
...

http://msdn.microsoft.com/en-us/library/hfw7t1ce(v=vs.71).aspx

当它来自接口的实现时,我不知道它不可能的调用基础方法。

答案 3 :(得分:0)

你不能在基类中调用显式接口方法,这里我解决了这个问题

我有两个界面 - &gt; Interface1和Interface2

public interface Interface1
{      
    string method2();      
}

public interface Interface2
{   
    string method22();

}

主类方法

class Program
{
    static void Main(string[] args)
    {

        class1 cls = new class1();
        string str = cls.method2();
    }
}

我的界面实现了类

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
}

答案 4 :(得分:0)

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();
        }
    }
}

答案 5 :(得分:0)

这是我的Roland Pihlakas版本的好解决方案。此版本支持整个继承链而不是直接基类。 Invoke方法包含其他参数,并且对于非函数方法存在void类型Invoke。

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);
}

答案 6 :(得分:0)

On选项将创建一个不完全实现接口的基类,而仅在子类上实现该接口。

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

这样做将允许您访问基类MethodA,而不必在MySyb中对其进行标记。