c# - 反射在评估堆栈上发出推送和附加参数
问题描述
我有工作代码来为函数创建代理:
// 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);
我正在尝试将加载的字符串推送到评估堆栈上,在此之前评估堆栈已经加载了输入参数,因此在调用跳转时参数对齐良好。但是现在我的函数需要接受一个额外的参数,我需要将加载的字符串推入堆栈。但是,当我运行它时,我得到一个错误:
公共语言运行时检测到无效程序。
在调用代理之前,如何在评估堆栈上弹出一个附加参数?
解决方案
事实证明,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();
}
推荐阅读
- java - 如何在具有自动保存功能的网站上设计 api 端点?
- ruby-on-rails - 使用 BUNDLE_FROZEN
- git - 隔离的“语义发布”docker 容器可以工作,但在 GitLab CI 中需要 40 分钟
- android - Firebase 没有从孩子那里提取信息
- reactjs - 如何将后端(嵌套)文件中的 multer 图像放到我的前端(反应)上?
- java - java为数据类创建时间范围属性
- powershell - 管道元素 Powershell 中的“,”后缺少表达式
- python - Pip 安装了我想使用的模块,但仍然出现“找不到模块”错误
- javascript - 缓存 observables 导致 mergeMap 出现问题
- json - 如何使用 az 命令为 jmespath 查询添加和条件