Comment appeler une méthode d'interface explicitement implémentée sur la classe de base

J'ai une situation, où deux classes (l'une dérivant de l'autre) implémentent explicitement la même interface:

interface I
{
  int M();
}

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

class B : A, I
{
  int I.M() { return 2; }
}

De l'implémentation de la classe dérivée de I.M(), j'aimerais appeler l'implémentation de la classe de base, mais je ne vois pas comment le faire. Ce que j'ai essayé jusqu'à présent est ceci (en Classe 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

Existe-t-il un moyen de le faire, sans avoir à implémenter une autre méthode d'assistance (Non explicite par interface)?


Mise à Jour:

Je sais c'est possible avec une méthode" helper " qui peut être appelée par la classe dérivée, par exemple:

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

Je peux également le changer pour implémenter l'interface de manière non explicite. Mais je me demandais si c'était possible sans ces solutions de contournement.

24
demandé sur MarqueIV 2011-05-12 13:50:33

6 réponses

Malheureusement, ce n'est pas possible.
Pas même avec une méthode d'aide. La méthode helper a les mêmes problèmes que votre deuxième tentative: this est de type B, même dans la classe de base et appellera l'implémentation de M dans 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(); }
}

La seule solution de contournement serait une méthode d'aide dans {[6] } qui est utilisée dans l'implémentation de A de 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(); }
}

Mais vous devrez fournir une méthode comme celle-ci aussi pour B s'il y aura un class C : B, I...

17
répondu Daniel Hilgarth 2011-05-12 10:04:28

C'est possible en utilisant la réflexion.
le code suit. J'ai ajouté la mise en cache comme optimisation de base, mais elle peut être optimisée plus loin en utilisant Delegate.CreateDelegate sur methodInfo. En outre, le nombre de paramètres et les contrôles de type peuvent être ajoutés en utilisant 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>

Ici est la source de mon inspiration.

10
répondu Roland Pihlakas 2012-08-21 09:24:35

Il est nécessaire explicitement?... Pouvez-vous utiliser une classe abstraite ou une classe au lieu de l'interface?

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

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

Je n'ai aucune idée de sa méthode de base d'appel impossible quand elle vient de l'implémentation de l'interface.

0
répondu Martin Drlík 2011-05-12 10:20:23

Vous ne pouvez pas appeler la méthode D'interface explicite dans la classe de base, ici j'ai résolu ce problème

J'ai deux interface -> Interface1 et 2

public interface Interface1
{      
    string method2();      
}

public interface Interface2
{   
    string method22();

}

Méthode de classe principale

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

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

Et mon interface implémentée classe

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
}
0
répondu Boopathi.Indotnet 2015-01-29 13:12:40
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
répondu Abhay Kumar 2016-09-04 06:21:15

Voici ma version de la belle solution de Roland Pihlakas. Cette version prend en charge toute la chaîne d'héritage au lieu de la classe de base immédiate. La méthode Invoke inclut des paramètres supplémentaires et il existe un type void Invoke pour les méthodes non fonctionnelles.

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
répondu Xtro 2017-10-23 05:01:59