実装クラスのメソッドの名前はまったく信頼できません。どのような名前でもかまいません。C#コンパイラはこれまで、メソッド名の前にインターフェイスのフルネームを付けるという規則を使用してきましたが、これは内部実装の詳細であり、F#などには当てはまりません。適切な方法は、実装にInterfaceMapping
を必要とする場合に使用することです。MethodInfo
たとえば、次の構造がある場合
namespace LibBar
{
[AttributeUsage(AttributeTargets.Method)]
public class AnswerAttribute : Attribute { }
public interface IFoo
{
void Hello();
int GetAnswer();
object WhoAmI();
}
}
そしてF#プロジェクトでは
namespace LibFoo
open LibBar
type Foo() =
interface IFoo with
[<Answer>]
member this.GetAnswer() = 42
member this.Hello() = printf "Hello, World!"
member this.WhoAmI() = this :> obj
GetAnswer()
リフレクションを介して呼び出したいだけの場合はMethodInfo
、インターフェイスのを取得するだけで十分です。
Foo obj = new Foo();
int answer = (int)typeof(IFoo)
.GetMethod("GetAnswer")
.Invoke(obj, null);
ただし、実装にAnswerAttributeがあるかどうかを確認したいとします。MethodInfo
その場合、インターフェイスにforメソッドを設定するだけでは不十分です。メソッドの名前は、"LibBar.IFoo.GetAnswer"
これがC#の場合ですが、使用するコンパイラーと言語の実装の詳細に関係なく機能するようにします。
private static MethodInfo GetMethodImplementation(Type implementationType, MethodInfo ifaceMethod)
{
InterfaceMapping ifaceMap = implementationType.GetInterfaceMap(ifaceMethod.DeclaringType);
for (int i = 0; i < ifaceMap.InterfaceMethods.Length; i++)
{
if (ifaceMap.InterfaceMethods[i].Equals(ifaceMethod))
return ifaceMap.TargetMethods[i];
}
throw new Exception("Method missing from interface mapping??"); // We shouldn't get here
}
...
Foo obj = new Foo();
MethodInfo ifaceMethod = typeof(IFoo).GetMethod("GetAnswer");
MethodInfo implementationMethod = GetMethodImplementation(typeof(Foo), ifaceMethod);
Console.WriteLine("GetAnswer(): {0}, has AnswerAttribute: {1}",
implementationMethod.Invoke(obj, null),
implementationMethod.GetCustomAttribute<AnswerAttribute>() != null);