Emit是.net Framework的Reflection的重要组成部分,其地位类同于Java中的cglib,在一些项目中特别是一些公共项目中不可或缺。在我的Kanas.net框架的数据囊中便使用了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。获取参数原型的方法非常简单,通过反射遍历所有的参数,取出类型来存入一个数组即可。

片段一:重载一个方法

private ILGenerator OverrideMethod(TypeBuilder typeBuilder, MethodInfo baseMethod)
{
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();
}

片段二:重载一个接口方法实现

private ILGenerator OverrideMethod(TypeBuilder typeBuilder, MethodInfo baseMethod)
{
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。

这样的情况下,比较简单的方式就是定义一个“伪方法”,将所有比较变态一点的参数都用到,目的只是为了反射而反射。例如可以定义这个方法:

private static void PseudCall(ref IntPtr p1, [In, Out] string[] p2, [MarshalAs(UnmanagedType.LPArray)] byte[] p3, ref SE_Error p4)
{
}

然后在运行时通过以下方式获取这个类型集合:

MethodInfo tmi = typeof(EngineFactory).GetMethod("PseudCall", BindingFlags.NonPublic | BindingFlags.Static);
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字节,就有绝对的安全保证。

实现这样的逻辑其实非常简单:

Label ln = methodGenerator.DefineLabel();
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应用中的常用技巧相关推荐

  1. excel中的常用技巧_在Excel中控制技巧

    excel中的常用技巧 Last week I listed a few tricks with the Shift key in Excel, and in the comments, Jon Pe ...

  2. C#DataGridView中的常用技巧

    只列出技巧部分,后面会有补充 0(最基本的技巧). 获取某列中的某行(某单元格)中的内容   this.currentposition = this.dataGridView1.BindingCont ...

  3. oracle 练习 50_萨克斯练习中的常用技巧

    1.吐音练习(善于运用舌头的辅助功能) 在初学时,我们通常用气来开始一个音,也就是利用吐气来开始声音,但大家有没有发现,我们经常会出现在气吹一半时才吹出音..这种情况在低音时尤其明显.所以,我们需要舌 ...

  4. 手持gps坐标转换参数求解方法及在excel中的实现_分享∣Arcgis中62个常用技巧系列二(21-40技巧)...

    二十一.融合后全部打散 ArcToolbox-> 数据管理 -> 属性 ->mergemultipart to singlepart 二十二.图层 关系处理 ArcToolbox-& ...

  5. Linux vi 行尾 ctrl,linux中vi使用技巧常用技巧和高级替换

    linux中vi使用技巧常用技巧和高级替换 模式切换: i,I   进入插入模式:i为从目前光标所在处插入:I为在目前所在列的第一个非空格的字符处开始插入. a,A  进入插入模式:a为从目前光标所在 ...

  6. vs c语言程序调试方法,VS2015中的常用调试技巧分享

    原标题:VS2015中的常用调试技巧分享 为什么要学习调试? 调试(Debug)是作为一个程序员必须要学会的东西,学会调试可以极大的提高开发效率,排错时间,很多人不喜欢调试,但我认为这是一个很不可取的 ...

  7. cdr 表格自动填充文字_极速office中表格的七个最常用技巧

    在日常的工作学习中,除了文字的排版,接触的第二大类就是表格了.表格的制作有时比文字的排版还麻烦,使用技巧不对常常事倍功半.以下整理了一些表格常用技巧,快来看看吧. 一.粘贴表格时怎样使格式不发生改变? ...

  8. excel函数去重_Excel 2010中去除重复项的几种常用技巧

    在工作中使用Excel 2010时,经常会有需要在对原始记录清单进行整理时,剔除其中一些重复项.接下来本文就来讲解下Excel 2010中去除重复项的几种常用技巧. 所谓的重复项,通常是指在Excel ...

  9. LaTeX中一些常用符号及编写技巧

    博客中阅读效果更佳哦:LaTeX中一些常用符号及编写技巧 希腊字母 小写形式 代码 大写形式 代码 α \alpha A \Alpha β \beta B \Beta δ \delta Δ \Delt ...

最新文章

  1. 五大质量工具详解及运用案例_掌握质量管理五大工具,实现九段质量管理成长...
  2. 读取文件卡顿_奥睿科IV300固态硬盘评测:35克,读取超900M/s?
  3. 百度分享自定义内容和图片
  4. 1650显卡能带动144hz吗_GTX1660显卡能称得起最甜吗?最猛GTX1660显卡性能测评
  5. django.db.utils.OperationalError: (1049, Unknown database 'djangodb')
  6. 如何JOPtionPane的showConfirmDialog对话框button设置监视器
  7. Linux服务器 通过ftp命令下载或上传文件
  8. 唱歌气沉丹田怎么做 气沉丹田的口诀
  9. 订餐系统(饿了某)java程序实现
  10. Java之String系列--intern方法的作用及原理
  11. TVS (瞬态二极管)
  12. 互联网下半场,苏宁“拼购村”如何打造现象级模式
  13. Matlab样条工具箱(Spline ToolBox)与曲线拟合
  14. pythone是什么_python是什么
  15. xilinx FPGA普通IO作PLL时钟输入
  16. 磁感应强度B,磁通量φ,磁场强度H,磁导率,磁链讲透了
  17. 用小米盒子搭建家庭NAS
  18. 直播回顾 | 第四期直播课堂:5G消息在工业领域的应用分享
  19. Arduino ESP32 基于Web服务端SD文件管理系统完善
  20. HTML静态页面之(盒子模型)

热门文章

  1. python使用界面-用python制作用户图形界面
  2. python实现http下载文件-Python HTTP下载文件并显示下载进度条功能的实现
  3. 编程软件python中的if用法-总结Python编程中函数的使用要点
  4. python在中小学教学中的应用-中小学Python教学的几点建议
  5. python进阶免费-菜鸟世界 -python进阶---生成器
  6. python干啥用的啊-python干什么用的
  7. python基础语法有哪些-Python基础语法一
  8. 免费学python的软件-初学python编程,有哪些不错的软件值得一用?
  9. python输出数据到excel-python实现数据导出到excel的示例--普通格式
  10. python读文件代码-简单了解Python读取大文件代码实例