在我读过的所有书中,他们经常说,你想要动态生成IL的情况并不多,但他们没有给出任何有意义的例子。
在看到Reflection.Emit作为游戏公司的工作要求后,我很好奇其他地方正在使用它。
我现在想知道在现实世界中是否有任何情况,这是解决问题的最佳方法。也许它被用作设计模式的实现?
注意我想象PostSharp / AOP使用它。
Expression.Compile
基本上是这样做的 - 这是一些LINQ的关键。
我目前正在使用反射发射来重新编写序列化API - 因为有时反射不够好。碰巧这也会让它产生dll(就像sgen的工作原理一样),允许完全静态的代码(我希望这会让iPhone变得友好)。
我还在HyperDescriptor中使用类似的方法来提供非常快速的基于名称的属性查找。
我也使用emit做以下事情:
所有都与SO问题有关。
最后,这种IL方法是protobuf-net“v2”的核心;这里的原因是它允许我在运行时拥有一个快速模型(通过IL动态编译它),并将其直接写入静态编译的dll,以便它适用于iPhone,Phone 7之类的东西等(缺少必要的元编程API)。
我最近用它创建了一个概念验证,用于编译一组在运行时非常昂贵的操作,并且速度提高了200%。操作是使用RegEx来解析一个大字符串,并循环匹配,使用Reflection来查找和实例化类型,以及一些其他不完全快的东西。通过使用IL emit,我创建了与委托类型(使用DynamicMethod)匹配并缓存它们的动态函数。我按照每个输入值做了一次正常的RegEx / Reflection舞蹈,以确定它应该做什么,然后使用StringBuilder将字符串连接为文字,而不是Reflection / Activator我现在可以在发出的IL中使用实际类型本身。这是一个有用的提示:不要试图自己写IL,除非你是一个sado-masochist。编写一个示例函数或键入C#,它可以执行您想要的操作,编译它,并使用Reflector或ILDASM查看生成的IL。然后使用Emit做类似的逻辑。另一个提示是你可以创建本地并将它们存储到变量中,然后使用Emit(OpCodes.Ldloc,myLocalVar)它将为你获取本地地址,而不必跟踪本地索引(即ldloc_1)。
Expression.Compile
来创建代码片段,通过编译给已编译委托的表达式来快速检索信息,这可以在将来执行。如果使用PropertyInfo.GetValue
,它会非常慢,但如果您创建一个表达式来访问属性并将其编译为委托(内部使用Reflection.Emit),则可以节省大量CPU时间。Reflection.Emit命名空间用于开发LinqPad。它有助于动态创建类型化的Datacontexts。看看这个链接http://www.linqpad.net/HowLINQPadWorks.aspx。
我喜欢探索更多AI-Inspired用于自学。它允许我们在运行时创建类或模块
例如,Entity Framework使用Reflection.Emit
在运行时构建代理类,它继承自模型类以提供延迟加载和更改跟踪。
我实际上正在开发自己的语言,我正在使用.NET Framework的Reflection.Emit
构建其编译器。
有人可能会认为使用C#构建编译器并不好,但实际上工作正常并且编译时性能足够好。此外,这显然与运行时性能无关,这将取决于CLR,而不是我的编译器(除了像运算符优先级这样的最小优化)。一旦我完成它,我就会在GitHub上发布它。
动态生成实现某种接口的mock object。执行此操作的示例框架:moq,rhino mocks。
我正在使用它作为一种动态创建动态代理来包装类的方法。 NHibernate使用相同的模式来代理对POCO对象的调用,而不是查询数据库。
任何时候你想要能够动态地“编写代码”(即创建一个新的函数等),你需要Emit
。
Castle DynamicProxy将它用于动态代理。然后,Castle的IoC容器Windsor和OR映射器ActiveRecord使用DynamicProxy。
DLR和DLR相关语言严重依赖Reflection.Emit
我记得在第8章中使用Relection.Emit
:Beautiful Code的“图像处理的动态代码生成”。基本上,作者专门用于对给定图像执行某组图像处理操作的功能,这反过来导致执行时间大大减少。
我在一个应用程序中使用它,其中必须通过反射重复访问属性(因为在编译时不知道属性名称)。
通过在运行时创建一个生成用于访问属性的代码的辅助类,生成的代码比原始的仅反射代码快一个数量级。
XMLSerializer实际上生成代码并在首次运行时编译它。如果您知道这种情况正在发生,您可以阅读有关如何调试XML序列化的this great blog post on Scott Hanselman's site。
模拟库也使用Reflection.Emit生成单元测试中使用的代理。