[英]C# Call and return an object from a static method in 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);
}
更新的代碼現在調用該方法,但似乎正在傳遞動態創建的類型的類型,而不是變量returnType。
至少一個問題是,即使從未彈出“此”引用( OpCodes.Ldarg_0
),它也從未被彈出(因為您正在調用靜態方法)。 我會嘗試刪除該行,看看它的表現是否更好。
另一個問題是您EmitCall
new Type[] { returnType }
傳遞給EmitCall
方法。 這是用於可選參數( params
)的,我懷疑您的方法實際上沒有任何參數。 因此,您也應該刪除該參數。
編輯:
基於注釋,您嘗試將靜態已知的System.Type
對象傳遞給要動態調用的方法。 這是可能的,但是您需要跳幾圈。
獲取對方法Type.GetTypeFromHandle
的MethodInfo
的引用:
MethodInfo getTypeFromHandle = typeof(Type).GetMethod("GetTypeFromHandle");
使用以下IL returnType
您的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);
此代碼的過渡堆棧行為為:
使用Opcodes.Ldtoken
將與指定Type
引用相對應的RuntimeTypeHandle
推入堆棧。
調用getTypeFromHandle
,將類型句柄從堆棧中彈出,然后將實際的System.Type
推入堆棧。
調用您的靜態方法,這會將Type
參數從堆棧中彈出,並將您自己方法的返回值壓入堆棧。
從方法返回。
在這里,表達式樹可能是一個更好的解決方案。 使用通過表達式的動態鍵入來創建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
函數本身需要通用參數,則可以將Expression.Call
語句中的null
更改為new Type[] { returnType }
。 如果為您傳入的每種類型生成一次該代碼,並且打算大量使用,則最好將這些Funcs緩存到Dictionary<Type, Func<Type, object>>
並僅構建一次(因為反復編譯表達式會浪費系統資源。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.