web-dev-qa-db-ja.com

基本クラスに明示的に実装されたインターフェイスメソッドを呼び出す方法

2つのクラス(一方が他方から派生)の両方が同じインターフェイスを明示的に実装する状況があります。

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

また、インターフェイスを非明示的に実装するように変更することもできます。しかし、これらの回避策がなくても可能かどうか疑問に思っていました。

29
M4N

残念ながら、それは不可能です。
ヘルパーメソッドでもありません。ヘルパーメソッドには、2回目の試行と同じ問題があります。thisは基本クラスでもタイプBであり、MBの実装を呼び出します。

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

唯一の回避策は、AAの実装で使用される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(); }
}

ただし、class C : B, I ..が存在する場合は、Bにもこのようなメソッドを提供する必要があります。

21
Daniel Hilgarth

リフレクションを使用することが可能です。
コードは次のとおりです。基本的な最適化としてキャッシュを追加しましたが、methodInfoで_Delegate.CreateDelegate_を使用することでさらに最適化できます。また、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>
_

ここ が私のインスピレーションの源です。

10
Roland Pihlakas

基本クラスで明示的なインターフェイスメソッドを呼び出すことはできません。ここでこの問題を解決しました

私は2つのインターフェースを持っています-> 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
}
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();
        }
    }
}
0
Abhay Kumar

これが私のバージョンのRolandPihlakasのNiceソリューションです。このバージョンは、直接の基本クラスではなく、継承チェーン全体をサポートします。 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);
}
0
Xtro

明示的に必要ですか?...インターフェイスの代わりに抽象クラスまたはクラスを使用できますか?

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

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

それがインターフェースの実装から来るとき、私はそれが不可能なコールベースメソッドであるとは思いません。

0
Martin Drlík