30

我有一种情况,两个类(一个从另一个派生)都显式地实现了相同的接口:

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

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

4

7 回答 7

22

不幸的是,这是不可能的。
甚至没有辅助方法。辅助方法与您的第二次尝试有相同的问题:this是 type 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(); }
}

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

但是您还需要提供这样的方法,因为B如果有class C : B, I...

于 2011-05-12T09:57:54.747 回答
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>

这里是我灵感的来源。

于 2012-08-20T19:38:11.427 回答
0

有必要明确吗?...您可以使用抽象类或类而不是接口吗?

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

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

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

于 2011-05-12T09:54:33.150 回答
0

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

我有两个接口-> 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
}
于 2015-01-29T13:12:40.847 回答
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();
        }
    }
}
于 2016-09-04T03:39:46.387 回答
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);
}
于 2017-10-23T05:01:59.643 回答
0

选项是创建一个不明确实现接口的基类,并且只在子类上实现接口。

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 中实现它。

于 2020-01-22T10:54:28.250 回答