使用IL Emit调用现有对象的方法 [英] Calling a method of existing object using IL Emit

查看:99
本文介绍了使用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() c $ c>。但是,无论到哪里看,我都能找到使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆