首页 > 解决方案 > 反射在评估堆栈上发出推送和附加参数

问题描述

我有工作代码来为函数创建代理:

// For this controller, I only want a Get method to server Get request
MethodBuilder myGetMethod =
    tb.DefineMethod("Get",
        MethodAttributes.Public,
        typeof(String), new Type[] { typeof(String) });

// Define parameters
myGetMethod.DefineParameter(
    position: 1, // 0 is the return value, 1 is the 1st param, 2 is 2nd, etc.
    attributes: ParameterAttributes.None,
    strParamName: "stringParam"
);

ILGenerator myMethodIL = myGetMethod.GetILGenerator();
Func<string, string> method = (v) => "Poop";
myMethodIL.Emit(OpCodes.Jmp, method.Method);
myMethodIL.Emit(OpCodes.Ret);

我想扩展函数以接受依赖。例如

Func<string, string, string> method = (v, s) => v + s + "Poop";

myMethodIL.Emit(OpCodes.Ldstr, "Hi");
myMethodIL.Emit(OpCodes.Jmp, method.Method);
myMethodIL.Emit(OpCodes.Ret);

我正在尝试将加载的字符串推送到评估堆栈上,在此之前评估堆栈已经加载了输入参数,因此在调用跳转时参数对齐良好。但是现在我的函数需要接受一个额外的参数,我需要将加载的字符串推入堆栈。但是,当我运行它时,我得到一个错误:

公共语言运行时检测到无效程序。

在调用代理之前,如何在评估堆栈上弹出一个附加参数?

标签: c#.net-corereflection.emit

解决方案


事实证明,Jump 语句仅在转发相同的参数时才有效,而不是弄清楚如何编写正确的 IL,我现在只是从 DI 容器中注入我需要的东西。

public static Type CompileResultType(string typeSignature, Dictionary<string, string> propDic)
{
    TypeBuilder tb = GetTypeBuilder(typeSignature);

    tb.SetParent(typeof(DynamicControllerBase));

    ConstructorBuilder ctor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

    foreach (var item in propDic)
    {
        CreateProperty(tb, item.Key, Type.GetType(item.Value));
    }

    // For this controller, I only want a Get method to server Get request
    MethodBuilder myGetMethod =
        tb.DefineMethod("Get",
            MethodAttributes.Public,
            typeof(String), new Type[] { typeof(Test), typeof(String) });

    // Define parameters
    var parameterBuilder = myGetMethod.DefineParameter(
        position: 1, // 0 is the return value, 1 is the 1st param, 2 is 2nd, etc.
        attributes: ParameterAttributes.None,
        strParamName: "test"
    );
    var attributeBuilder
        = new CustomAttributeBuilder(typeof(FromServicesAttribute).GetConstructor(Type.EmptyTypes), Type.EmptyTypes);
    parameterBuilder.SetCustomAttribute(attributeBuilder);

    // Define parameters
    myGetMethod.DefineParameter(
        position: 2, // 0 is the return value, 1 is the 1st param, 2 is 2nd, etc.
        attributes: ParameterAttributes.None,
        strParamName: "stringParam"
    );

    // Generate IL for method.
    ILGenerator myMethodIL = myGetMethod.GetILGenerator();
    Func<string, string> method = (v) => "Poop";

    Func<Test, string, string> method1 = (v, s) => v.Name + s;

    myMethodIL.Emit(OpCodes.Jmp, method1.Method);
    myMethodIL.Emit(OpCodes.Ret);

    return tb.CreateType();
}

推荐阅读