How to call an explicitly implemented interface-method on the base class

后端 未结 7 1149
死守一世寂寞
死守一世寂寞 2020-12-05 09:56

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
{
          


        
相关标签:
7条回答
  • 2020-12-05 10:25

    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.

    0 讨论(0)
  • 2020-12-05 10:26

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

    0 讨论(0)
  • 2020-12-05 10:26
    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();
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-05 10:36

    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);
    }
    
    0 讨论(0)
  • 2020-12-05 10:40

    On option would be to create a base class that doesn't excplicitly implement an interface, and to only implement the interface on the subclass.

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

    Doing this will allow you to access the base classes MethodA without having to implemnet it in MySyb.

    0 讨论(0)
  • 2020-12-05 10:41

    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.

    0 讨论(0)
提交回复
热议问题