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; }
}
_
また、インターフェイスを非明示的に実装するように変更することもできます。しかし、これらの回避策がなくても可能かどうか疑問に思っていました。
残念ながら、それは不可能です。
ヘルパーメソッドでもありません。ヘルパーメソッドには、2回目の試行と同じ問題があります。this
は基本クラスでもタイプB
であり、M
の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(); }
}
ただし、class C : B, I
..が存在する場合は、B
にもこのようなメソッドを提供する必要があります。
リフレクションを使用することが可能です。
コードは次のとおりです。基本的な最適化としてキャッシュを追加しましたが、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>
_
ここ が私のインスピレーションの源です。
基本クラスで明示的なインターフェイスメソッドを呼び出すことはできません。ここでこの問題を解決しました
私は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
}
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();
}
}
}
これが私のバージョンの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);
}
明示的に必要ですか?...インターフェイスの代わりに抽象クラスまたはクラスを使用できますか?
interface ISample {}
class A : ISample {}
class B : A {}
...
base.fun();
...
http://msdn.Microsoft.com/en-us/library/hfw7t1ce(v = vs.71).aspx
それがインターフェースの実装から来るとき、私はそれが不可能なコールベースメソッドであるとは思いません。