繁体   English   中英

使用 IL Emit 调用现有 object 的方法

[英]Calling a method of existing object using IL Emit

我正在尝试编写一个基于属性的拦截器(类似于DynamicProxy )。 这个想法是,基于某些自定义属性,将调用该属性内的方法,即

  • 在调用实际方法之前调用属性 class 内的方法。
  • 调用实际方法。

我可以使用MethodBuilderTypeBuilder覆盖现有方法。 但是,我不知道如何调用 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创建对象的新实例的示例。 我不想用这个,因为属性可能有参数。

我想不出任何调用属性 class 中的方法(它将替换 step1 注释)。

编辑:根据评论,我试图在 IL 中移动代码的GetCustomAttribute部分。 这就是我现在所拥有的

il.Emit(OpCodes.Ldtoken, methodToOverride);
il.Emit(OpCodes.Ldtoken, typeof(ProxyMethod));
il.Emit(OpCodes.Call, typeof(Attribute).GetMethod("GetCustomAttribute", new [] { typeof(MemberInfo), typeof(Type) }));

它给我一个错误。 有小费吗?

动态代码生成总是有点烦人。 让我们首先编写一些辅助方法来摆脱所有.GetMethod的东西:

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下面是我们如何检索它并调用它:

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实际上并不存在,这是作为扩展方法实现的。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM