使用 IL Emit 调用现有对象的方法 [英] Calling a method of existing object using IL Emit
问题描述
我正在尝试编写一个基于属性的拦截器(类似于DynamicProxy
).这个想法是,基于某些自定义属性,将调用该属性内的方法,即
I am attempting to write an attribute based interceptor (something similar to DynamicProxy
). The idea being, based on certain custom attributes, a method inside that attribute would be called, i.e.
- 在调用实际方法之前调用属性类中的方法.
- 调用实际方法.
我能够使用 MethodBuilder
和 TypeBuilder
覆盖现有方法.但是,我不知道如何调用Attribute内部的方法.
I am able to override existing method using MethodBuilder
and TypeBuilder
. However, I can't figure out how to call the method inside the Attribute.
我的代码:
static void CreateMethods<T>(TypeBuilder tb)
{
foreach (var methodToOverride in typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly))
{
var attribute = (ProxyMethod)methodToOverride.GetCustomAttribute(typeof(ProxyMethod));
if (attribute == null)
continue;
MethodBuilder methodBuilder = tb.DefineMethod(
methodToOverride.Name,
MethodAttributes.Public
| MethodAttributes.HideBySig
| MethodAttributes.NewSlot
| MethodAttributes.Virtual
| MethodAttributes.Final,
CallingConventions.HasThis,
methodToOverride.ReturnType,
Type.EmptyTypes
);
ILGenerator il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldstr, "The I.M implementation of C"); //step1
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //step1
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, methodToOverride);
il.Emit(OpCodes.Ret);
tb.DefineMethodOverride(methodBuilder, methodToOverride);
}
}
我认为我应该做的是将 attribute
加载到堆栈上,然后通过发出对 MethodInfo
的调用来调用 attribute.attributeMethod()
.然而,在我所看到的任何地方,我都可以找到使用 OpCodes.NewObj
创建对象的新实例的示例.我不想用这个,因为属性可能有参数.
What I think I should do is load attribute
onto stack, then call attribute.attributeMethod()
by emitting a call to the MethodInfo
. However, everywhere I look, I can find examples of creating a new instance of the objected using OpCodes.NewObj
. I don't want to use this, because attributes may have parameters.
我想不出在属性类中调用方法(这将取代 step1 注释).
I can't think of any of calling the method inside attribute class (which would replace step1 comment).
根据评论,我试图移动 IL 中代码的 GetCustomAttribute
部分.这就是我现在拥有的
Based on comments, I'm trying to move the GetCustomAttribute
part of the code in IL. This is what I have right now
il.Emit(OpCodes.Ldtoken, methodToOverride);
il.Emit(OpCodes.Ldtoken, typeof(ProxyMethod));
il.Emit(OpCodes.Call, typeof(Attribute).GetMethod("GetCustomAttribute", new [] { typeof(MemberInfo), typeof(Type) }));
它给我带来了错误.有什么提示吗?
It throws an error for me. Any tips?
推荐答案
动态代码生成总是有点烦人.让我们首先编写一些辅助方法来摆脱所有 .GetMethod
的东西:
Dynamic code generation is always kind of annoying. Let's cook up some helper methods first to get rid of all the .GetMethod
stuff:
static class Method {
public static MethodInfo Of<TResult>(Expression<Func<TResult>> f) => ((MethodCallExpression) f.Body).Method;
public static MethodInfo Of<T>(Expression<Action<T>> f) => ((MethodCallExpression) f.Body).Method;
public static MethodInfo Of(Expression<Action> f) => ((MethodCallExpression) f.Body).Method;
}
现在假设我们有 ProxyMethodAttribute
及其方法 MyMethod
-- 以下是我们检索和调用它的方法:
Now let's say we have ProxyMethodAttribute
and its method MyMethod
-- here's how we'd retrieve that and call it:
il.Emit(OpCodes.Ldtoken, methodToOverride);
il.Emit(OpCodes.Call, Method.Of(() => MethodBase.GetMethodFromHandle(default(RuntimeMethodHandle))));
il.Emit(OpCodes.Ldtoken, typeof(ProxyMethodAttribute));
il.Emit(OpCodes.Call, Method.Of(() => Type.GetTypeFromHandle(default(RuntimeTypeHandle))));
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Call, Method.Of(() => Attribute.GetCustomAttribute(default(MemberInfo), default(Type), default(bool))));
il.Emit(OpCodes.Callvirt, Method.Of((ProxyMethodAttribute a) => a.MyMethod()));
注意我们如何需要调用 GetXXXFromHandle
以从生成的元数据标记生成实际实例,以及我们如何需要对 Attribute.GetCustomAttribute
(MethodInfo.GetCustomAttribute
实际上并不存在,这是作为扩展方法实现的.)
Note how we need to call GetXXXFromHandle
to produce actual instances from the metadata tokens generated, and how we need a more involved call to Attribute.GetCustomAttribute
(MethodInfo.GetCustomAttribute
doesn't actually exist, this is implemented as an extension method.)
这篇关于使用 IL Emit 调用现有对象的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!