3

これは、ここで提供されるソリューションの拡張です。オブジェクトを返す静的メソッドを作成しました。私の目標は、実行時に定義する型の動的メソッドを記述して、この静的メソッドが返すオブジェクトを返すことです。これまでの私のコード:

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

更新されたコードはメソッドを呼び出すようになりましたが、変数 returnType ではなく、動的に作成された型の型を渡しているようです。

4

2 に答える 2

4

少なくとも 1 つの問題は、"this" 参照 ( OpCodes.Ldarg_0) が決してポップされないにもかかわらず、スタックにプッシュしていることです (静的メソッドを呼び出しているため)。その行を削除して、動作が改善するかどうかを確認します。

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

編集:

コメントに基づいて、System.Type動的に呼び出しているメソッドに静的に知られているオブジェクトを渡そうとしています。これは可能ですが、いくつかのフープをジャンプする必要があります。

  1. MethodInfoメソッドの への参照を取得しますType.GetTypeFromHandle

    MethodInfo getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle");
    
  2. 次の IL の行を使用してreturnType、スタックにプッシュします。

    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を使用して、指定されTypeた参照に対応する をスタックにプッシュしますOpcodes.Ldtoken

  2. getTypeFromHandleタイプ ハンドルをスタックからポップし、実際のハンドルをスタックにプッシュする呼び出しSystem.Type

  3. 静的メソッドを呼び出します。これにより、Type引数がスタックからポップされ、独自のメソッドの戻り値がスタックにプッシュされます。

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

于 2012-03-08T19:46:22.093 に答える
1

ここでは、式ツリーがより良い解決策になる可能性があります。Func<Type, object>式による動的型付けを使用して を作成するのは非常に簡単です。

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

ここで、ObjectStore に汎用パラメーターが必要な場合はtypeof(ObjectStore)typeof(ObjectStore).MakeGenericType(returnType). GetStoredObject関数自体が汎用パラメーターを必要とする場合はnullExpression.Callステートメント内の を に変更しnew Type[] { returnType }ます。これが渡す型ごとに 1 回生成され、これを頻繁に使用する予定がある場合は、これらの Func を にキャッシュし、Dictionary<Type, Func<Type, object>>1 回だけビルドすることをお勧めします (式を繰り返しコンパイルするとシステム リソースが無駄になるため)。 .

于 2012-03-08T19:59:09.613 に答える