Emit应用中的常用技巧
Emit的典型应用如下:
1.动态代理,参见:http://www.castleproject.org/index.php/DynamicProxy
2.解除对非托管dll的绑定,参见:http://www.codeproject.com/dotnet/DynamicDllImport.asp
3.工具及IDE插件的开发
4.公共代码安全模块的开发
本文与大家分享一些常用的技巧。
1.布局
定义动态类的一种比较好的方式是定义一个基类,留下一些虚拟或抽象方法由动态类继承。比较合理的方案是在这个基类中定义一个静态方法,返回动态类型的Type实例甚至直接返回该基类的实例(或者称代理)。在Emit布局中需要考虑的问题是Assembly的名称和类型名称,不可以重复,如果有可能由Emit生成多个动态类型,并且不是一次生成,这个问题就会突出出来。我的意见是Assembly的名称采用固定名称头加上随机字符串名称尾的方式。类型名称则可以采用手工方式定义来避免重复。
2.重载方法(override)
在所有Method Declare的方法中,重载一个方法是最简单的了。你可以简单地使用反射就可以拿到所有的Parameter定义所需要的Type,而不需要挖空心思去寻找类型的反射实例。
重载方法有两种情况,一种是重载基类的虚拟或者抽象方法,另一种是实现接口方法(严格说并不是重载)。这两种情况公共的地方是MethodAttributes中必须包括MethodAttributes.HideBySig和MethodAttributes.Virtual。前一种情况必须还包括MethodAttributes.ReuseSlot,而后一种情况必须还包括MethodAttributes.NewSlot。获取参数原型的方法非常简单,通过反射遍历所有的参数,取出类型来存入一个数组即可。
片段一:重载一个方法
{
ParameterInfo[] paramInfos = baseMethod.GetParameters();
Type[] argTypes = new Type[paramInfos.Length];
int i = 0;
foreach (ParameterInfo pi in paramInfos)
{
argTypes[i ++] = pi.ParameterType;
}
MethodAttributes attributes = MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.ReuseSlot//MethodAttributes.NewSlot;
if (baseMethod.IsPublic)
{
Attributes |= MethodAttributes.Public;
}
MethodBuilder method = typeBuilder.DefineMethod(baseMethod.Name, attributes, baseMethod.ReturnType, argTypes);
return method.GetILGenerator();
}
片段二:重载一个接口方法实现
{
ParameterInfo[] paramInfos = baseMethod.GetParameters();
Type[] argTypes = new Type[paramInfos.Length];
int i = 0;
foreach (ParameterInfo pi in paramInfos)
{
argTypes[i ++] = pi.ParameterType;
}
MethodAttributes attributes = MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.ReuseSlot//MethodAttributes.NewSlot | MethodAttributes.Public;
MethodBuilder method = typeBuilder.DefineMethod(baseMethod.Name, attributes, baseMethod.ReturnType, argTypes);
typeBuilder.DefineMethodOverride(method, baseMethod);
return method.GetILGenerator();
}
3.加入到AppDomain(应用域)
如果Emit返回动态类型后,立即建立实例并输出参与后期的行为,不涉及AppDomain问题。但如果输出的只是动态类型,就必须将动态类型所在的Assembly加入到AppDomain中。类型是元数据,当然是Singleton的,所以采用一个静态的Hashtable来管理就够了。每生成一个动态类型就将该类型所在的Assembly以类型为关键字存入Hashtable,然后给定AppDomain的CurrentDomain实例的AssemblyResolve事件,在事件Handler中查找指定类型对应的Assembly作为返回。
需要特别说明的是,给CurrentDomain设定事件只需要在每次定义Assembly时设定,而不是定义每个动态类型时设定。
4.获取参数类型
在C#.net中获取类型的Type实例并那么自由。例如void*这样的参数类型就必须用到unsafe限定。而带有ref或者out限定符以及带有“伪标签”的参数就更难获取参数类型的Type实例了。例如[In, Out] string。
这样的情况下,比较简单的方式就是定义一个“伪方法”,将所有比较变态一点的参数都用到,目的只是为了反射而反射。例如可以定义这个方法:
{
}
然后在运行时通过以下方式获取这个类型集合:
ParameterInfo[] pis = tmi.GetParameters();
Type[] types = new Type[pis.Length];
for (int i = 0; i < pis.Length; i ++)
{
types[i] = pis[i].ParameterType;
}
5.循环分支
大部分情况下,Emit生成的动态类型及方法都不能太复杂,所以采用“短分支”指令是很自然的事情。但是凡事总有例外,特别是有些代码是通过循环来实现的,在这种情况下,就有可能通过“短分支”想实现长距离的代码跳转。
例如在C#中:
case 1:
…
break;
case 2:
…
break;
…
case 100:
…
break;
}
以上代码用MSIL实现时,case 1的break有可能无法通过短跳转跳到分支以外,但是按以下方式实现却是非常保险的:
case 1:
…
goto b1;
case 2:
…
b1:
goto b2;
…
case 100:
…
b99:
goto b100;
}
b100:
…
这样只要保证每个case中生成的代码长度不超过128字节,就有绝对的安全保证。
实现这样的逻辑其实非常简单:
bool isFirst = true;
foreach (int i in list)
{
// 生成case中的代码
……
// 此处需要跳转
if (isFirst)
{
isFirst = false;
}
else
{
methodGenerator.MarkLabel(ln);
ln = methodGenerator.DefineLabel();
}
methodGenerator.Emit(OpCodes.Br_S, ln);
// 不跳转的后续处理
…
}
// 退出前的处理
…
methodGenerator.MarkLabel(ln);
转载于:https://www.cnblogs.com/Barton131420/articles/217905.html
Emit应用中的常用技巧相关推荐
- excel中的常用技巧_在Excel中控制技巧
excel中的常用技巧 Last week I listed a few tricks with the Shift key in Excel, and in the comments, Jon Pe ...
- C#DataGridView中的常用技巧
只列出技巧部分,后面会有补充 0(最基本的技巧). 获取某列中的某行(某单元格)中的内容 this.currentposition = this.dataGridView1.BindingCont ...
- oracle 练习 50_萨克斯练习中的常用技巧
1.吐音练习(善于运用舌头的辅助功能) 在初学时,我们通常用气来开始一个音,也就是利用吐气来开始声音,但大家有没有发现,我们经常会出现在气吹一半时才吹出音..这种情况在低音时尤其明显.所以,我们需要舌 ...
- 手持gps坐标转换参数求解方法及在excel中的实现_分享∣Arcgis中62个常用技巧系列二(21-40技巧)...
二十一.融合后全部打散 ArcToolbox-> 数据管理 -> 属性 ->mergemultipart to singlepart 二十二.图层 关系处理 ArcToolbox-& ...
- Linux vi 行尾 ctrl,linux中vi使用技巧常用技巧和高级替换
linux中vi使用技巧常用技巧和高级替换 模式切换: i,I 进入插入模式:i为从目前光标所在处插入:I为在目前所在列的第一个非空格的字符处开始插入. a,A 进入插入模式:a为从目前光标所在 ...
- vs c语言程序调试方法,VS2015中的常用调试技巧分享
原标题:VS2015中的常用调试技巧分享 为什么要学习调试? 调试(Debug)是作为一个程序员必须要学会的东西,学会调试可以极大的提高开发效率,排错时间,很多人不喜欢调试,但我认为这是一个很不可取的 ...
- cdr 表格自动填充文字_极速office中表格的七个最常用技巧
在日常的工作学习中,除了文字的排版,接触的第二大类就是表格了.表格的制作有时比文字的排版还麻烦,使用技巧不对常常事倍功半.以下整理了一些表格常用技巧,快来看看吧. 一.粘贴表格时怎样使格式不发生改变? ...
- excel函数去重_Excel 2010中去除重复项的几种常用技巧
在工作中使用Excel 2010时,经常会有需要在对原始记录清单进行整理时,剔除其中一些重复项.接下来本文就来讲解下Excel 2010中去除重复项的几种常用技巧. 所谓的重复项,通常是指在Excel ...
- LaTeX中一些常用符号及编写技巧
博客中阅读效果更佳哦:LaTeX中一些常用符号及编写技巧 希腊字母 小写形式 代码 大写形式 代码 α \alpha A \Alpha β \beta B \Beta δ \delta Δ \Delt ...
最新文章
- 五大质量工具详解及运用案例_掌握质量管理五大工具,实现九段质量管理成长...
- 读取文件卡顿_奥睿科IV300固态硬盘评测:35克,读取超900M/s?
- 百度分享自定义内容和图片
- 1650显卡能带动144hz吗_GTX1660显卡能称得起最甜吗?最猛GTX1660显卡性能测评
- django.db.utils.OperationalError: (1049, Unknown database 'djangodb')
- 如何JOPtionPane的showConfirmDialog对话框button设置监视器
- Linux服务器 通过ftp命令下载或上传文件
- 唱歌气沉丹田怎么做 气沉丹田的口诀
- 订餐系统(饿了某)java程序实现
- Java之String系列--intern方法的作用及原理
- TVS (瞬态二极管)
- 互联网下半场,苏宁“拼购村”如何打造现象级模式
- Matlab样条工具箱(Spline ToolBox)与曲线拟合
- pythone是什么_python是什么
- xilinx FPGA普通IO作PLL时钟输入
- 磁感应强度B,磁通量φ,磁场强度H,磁导率,磁链讲透了
- 用小米盒子搭建家庭NAS
- 直播回顾 | 第四期直播课堂:5G消息在工业领域的应用分享
- Arduino ESP32 基于Web服务端SD文件管理系统完善
- HTML静态页面之(盒子模型)
热门文章
- python使用界面-用python制作用户图形界面
- python实现http下载文件-Python HTTP下载文件并显示下载进度条功能的实现
- 编程软件python中的if用法-总结Python编程中函数的使用要点
- python在中小学教学中的应用-中小学Python教学的几点建议
- python进阶免费-菜鸟世界 -python进阶---生成器
- python干啥用的啊-python干什么用的
- python基础语法有哪些-Python基础语法一
- 免费学python的软件-初学python编程,有哪些不错的软件值得一用?
- python输出数据到excel-python实现数据导出到excel的示例--普通格式
- python读文件代码-简单了解Python读取大文件代码实例