3

Reflection.Emitを使用して、実行時に複数のインターフェイスから継承するクラスを発行しようとしていますが、どのインターフェイスを事前に知ることができません。

MSDN / TypeBuilder.DefineMethodOverrideによると:

基本クラスのメソッドをオーバーライドしたり、インターフェイスのメソッドを実装したりするには、オーバーライドまたは実装するメソッドと同じ名前とシグネチャを持つメソッドを発行するだけです。

インターフェイスメソッドをオーバーライドするコードは次のとおりです。

private void OverrideMethod(TypeBuilder typeBuilder, 
                            Type interfaceToOverride,
                            MethodInfo methodToOverride)
{
    // Create the method stub
    MethodBuilder methodBuilder = typeBuilder.DefineMethod(
        methodToOverride.Name,
        MethodAttributes.Public
        | MethodAttributes.HideBySig
        | MethodAttributes.NewSlot
        | MethodAttributes.Virtual
        | MethodAttributes.Final,
        CallingConventions.HasThis,
        methodToOverride.ReturnType,
        methodToOverride.GetParameters().Select(p => p.ParameterType).ToArray()
    );

    // Implement the overriding method
    ILGenerator il = methodBuilder.GetILGenerator();

    // ... a bunch of calls to il.Emit ...

    // Return 
    il.Emit(OpCodes.Ret);
}

これは、同じ名前のメソッドを持つ2つのインターフェイスから継承する場合を除いて機能します。明らかに、これはメソッドに完全修飾名を付けていないためです。これを正しく行う方法がわかりません。

に変更methodToOverride.NameしてinterfaceToOverride.FullName + "." + methodToOverride.Nameも機能しませんでした:「TypeLoadException:クラスに実装がありません。

部分的に機能しDefineMethodOverrideましたが、ネストされたインターフェイスに対してテストしたときに、何らかの理由で機能しませんでした。また、上記のリンク先のドキュメントには、これを行わないように明示的に記載されています。

この問題を回避するための正しいアプローチは何ですか?

4

1 に答える 1

2

これを行う適切な方法は、という名前のメソッドを定義してから<InterfaceName>.<MethodName>を呼び出すことTypeBuilder.DefineMethodOverrideです。

DefineMethodOverrideメソッドは、メソッド本体とメソッド宣言の名前が異なる場合に使用されます。

あなたの場合、メソッド本体名はですが<InterfaceName>.<MethodName>、メソッド宣言名は<MethodName>です。したがって、を使用しても問題ありませんTypeBuilder.DefineMethodOverride

使用例

private void OverrideMethod(TypeBuilder typeBuilder, 
                            Type interfaceToOverride,
                            MethodInfo methodToOverride)
{
    // Create the method stub
    MethodBuilder methodBuilder = typeBuilder.DefineMethod(
        /* Change method name here */
        string.Format("{0}.{1}", interfaceToOverride.FullName,
            methodToOverride.Name),
        MethodAttributes.Public
        | MethodAttributes.HideBySig
        | MethodAttributes.NewSlot
        | MethodAttributes.Virtual
        | MethodAttributes.Final,
        CallingConventions.HasThis,
        methodToOverride.ReturnType,
        methodToOverride.GetParameters().Select(p => p.ParameterType).ToArray()
    );

    // Implement the overriding method
    ILGenerator il = methodBuilder.GetILGenerator();

    // ... a bunch of calls to il.Emit ...

    // Return 
    il.Emit(OpCodes.Ret);

    // And define a methodimpl, which consists of a pair of metadata tokens.
    // One token points to an implementation, and the other token points
    // to a declaration that the body implements
    typeBuilder.DefineMethodOverride(methodBuilder, methodToOverride);
}

ノート

実際には、(を使用してTypeBuilder.DefineMethod任意の名前でメソッドを定義できます。ただし、これとは異なる必要があり、メソッド宣言を使用してメソッド本体を「リンク」する必要があり<MethodName>ます。TypeBuilder.DefineMethodOverride

于 2013-02-04T21:32:09.427 に答える