2012-03-08 12 views
2

に静的メソッドからオブジェクトを返すこれはhere提供ソリューションの拡張です。私はオブジェクトを返す静的メソッドを作成しました。私の目標は、実行時にこの静的メソッドが返すオブジェクトを返すように定義した型の動的メソッドを作成することです。これまでの私のコード:C#のコールおよびIL

// type builder and other prep stuff removed for sake of space and reading 

private void EmitReferenceMethodBody(Type returnType) 
{ 
    MethodBuilder builder = 
    typeBuilder.DefineMethod(
        method.Name, 
        MethodAttributes.Virtual | MethodAttributes.Public, 
        method.CallingConvention, 
        method.ReturnType, 
        typeArray1); 
    builder.InitLocals = true; 
    ILGenerator gen = builder.GetILGenerator(); 
    MethodInfo getStoredObject = typeof(ObjectStore).GetMethod("GetStoredObject",     BindingFlags.Public | BindingFlags.Static);   
    MethodInfo getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle");    

    gen.Emit(OpCodes.Ldtoken, returnType); 
    gen.Emit(OpCodes.Call, getTypeFromHandle); 
    gen.Emit(OpCodes.Call, getStoredObject); 
    gen.Emit(OpCodes.Ret); 
} 

は、更新されたコードは現在、メソッドを呼び出すのではなく、その後、動的に作成された型の型変数を渡す戻り値のように見えます。

答えて

4

少なくとも一つの問題は、(あなたが静的メソッドを呼び出しているので)あなたはそれがポップされることはありませんにもかかわらず、スタック上に「this」参照(OpCodes.Ldarg_0)を推進しているということです。私はその行を削除して、それがよりうまく動作するかどうかを確認します。

もう一つの問題は、あなたがEmitCall方法にnew Type[] { returnType }に渡しているということです。これはオプションの引数(params)を対象としており、実際にはあなたのメソッドにはパラメータがないと思われます。したがって、その引数も削除する必要があります。

編集:コメントに基づいて

、あなたが動的に呼び出すメソッドを静的に既知のSystem.Typeオブジェクトを渡すしようとしています。これは可能ですが、いくつかのフープを飛び越える必要があります。スタックにごreturnTypeをプッシュする

MethodInfo getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle"); 
  • 利用ILの次の行を:

    1. 方法Type.GetTypeFromHandleためMethodInfoへの参照を取得します

      gen.Emit(OpCodes.Ldtoken, returnType); 
      gen.Emit(OpCodes.Call, getTypeFromHandle); 
      

    合計すると、コードは次のようになります。

    MethodInfo getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle"); 
    gen.Emit(OpCodes.Ldtoken, returnType); 
    gen.Emit(OpCodes.Call, getTypeFromHandle); 
    gen.EmitCall(OpCodes.Call, getStoredObject);     
    gen.Emit(OpCodes.Ret); 
    

    このコードの過渡スタック動作は、次のとおり

    1. プッシュRuntimeTypeHandle

      Opcodes.Ldtokenを使用してスタックに指定Type基準に対応します。

    2. Invoke getTypeFromHandle型ハンドルをスタックからポップし、実際のSystem.Typeをスタックにプッシュします。

    3. Type引数をスタックから取り除き、自分のメソッドの戻り値をスタックにプッシュする静的メソッドを呼び出します。

    4. このメソッドから戻ります。

  • +0

    したがって、load arg 0 emitを削除すると、これは静的メソッドを呼び出すことができますが、returnType変数を静的メソッドに渡したいのですが、 'this'を渡しているようです。私が静的メソッドをデバッグするとき、 'Type'型のparamはreturnTypeの値ではなく、私が作成した動的クラスの型です。 – OnResolve

    +0

    メソッドのシグネチャが次のようになっていることを確認してください: 'Object GetStoredObject(Type returnType);'。もしそうなら、あなたは本当に引数を渡す必要があります。しかし、あなたが実際に渡そうとしているのは、「タイプ」ですか? –

    +0

    "public static Object GetStoredObject(Type contract)" EmitReferenceMethodBody(Type returnType)という上記のメソッドは、静的メソッドに渡すタイプを渡します。 – OnResolve

    1

    ここでは表現木が良い解決法かもしれません。式を使って動的タイピングを使用してFunc<Type, object>を作成するのはかなり簡単です。ObjectStoreのが一般的なパラメータを必要とする場合

    ParameterExpression paramEx = Expression.Parameter(typeof(Type), "paramObject"); 
    Expression callExpression = Expression.Call(typeof(ObjectStore), "GetStoredObject", null, paramEx); 
    Expression<Func<Type, object>> funcExpression = Expression.Lambda<Func<Type, object>>(callExpression, paramEx); 
    Func<Type, object> actualFunc = funcExpression.Compile(); 
    

    さて、あなたはtypeof(ObjectStore).MakeGenericType(returnType)typeof(ObjectStore)を置き換えます。 GetStoredObject関数自体に汎用パラメータが必要な場合は、ステートメントのnullnew Type[] { returnType }に変更します。これが渡されるタイプごとに1回生成され、これをたくさん使用する予定の場合は、これらのFuncをDictionary<Type, Func<Type, object>>にキャッシュして一度しか構築しないことをお勧めします(繰り返しコンパイルするとシステムリソースが浪費される)。

    関連する問題