Reflection.Emit的真实世界应用

44

在我阅读过的有关反射的所有书籍中,它们经常说生成动态IL并不是很常见的情况,但它们没有给出任何实际应用的例子。

看到一家游戏公司将 Reflection.Emit 作为工作要求后,我好奇还有哪些地方正在使用它。

现在我想知道您是否见过真实世界中使用 Reflection.Emit 是解决问题的最佳方案的情况。也许它被用作设计模式的实现?

注意: 我想象 PostSharp / AOP 使用它。


2
PostSharp 执行编译后步骤,但不会在运行时发出代码。 - Daniel Brückner
3
听起来很适合作为社区维基的候选人。 :) - alimbada
2
我知道现在有点晚了,但我们正在使用的这个网站(stackoverflow.com)正在大量使用Dapper,它大量使用Reflection.Emit。 - YS.
我以为Dapper使用CodeDOM来生成模型类。 - Water Cooler v2
17个回答

15

Expression.Compile的本质是这样的——这是LINQ中一些关键内容的关键。

我目前正在使用反射发射(reflection emit)重新编写序列化API,因为有时候反射并不能胜任。正巧这也允许它生成dll文件(类似于sgen的方式),从而实现完全的静态代码(我希望这将使其对iPhone更加友好)。

我还在HyperDescriptor中使用了类似的方法,以提供非常快速的基于名称的属性查找。

我还使用发射做了一些事情,比如:

全部与Stack Overflow上的问题相关。

最后,这种IL方法是protobuf-net“v2”核心的原因;原因在于它允许我在运行时拥有快速的模型(通过即时编译IL来编译它),并且能够将同样的代码直接编写到静态编译的dll中,以便在iPhone、Phone 7等设备上使用(这些设备缺乏必要的元编程API)。


请问您能提供一下您所提到的那些问题的链接吗? - Jordão

13

8

我将其用作一种在运行时创建动态代理以包装类的方法。NHibernate使用相同的模式将对POCO对象的调用代理到查询数据库。

任何时候,您想要能够动态“编写代码”(即创建新函数等),都需要Emit


3
System.Linq.Expressions命名空间中引入Compile()方法之前,这种情况曾经更为普遍。 - Sam Harwell
我应该补充一下,当我将一些 Emit 代码切换到表达式代码时,一些幽灵错误悄然自行解决了。对于基本上适用的每个地方来说,这样做更加清晰和易于维护。 - Sam Harwell
Expression Compile 方法有一个巨大的限制,只能在没有语句体的 lambda 上工作。 - Eli Dagan

7

Castle DynamicProxy用于创建动态代理。然后,Castle的IoC容器Windsor和OR映射器ActiveRecord使用DynamicProxy。


1
......还有Rhino Mocks和Moq以及NHibernate和整套其他框架和应用程序 ;) - Krzysztof Kozmic

6
DLR和DLR相关语言在很大程度上依赖于Reflection.Emit。

3
我记得在Beautiful Code的第8章“用于图像处理的即时代码生成”中看到了Relection.Emit的使用。基本上,作者针对给定的图像专门设计了一个函数来执行某个特定的图像处理操作,这反过来又导致执行时间大大缩短。

3

我曾在一个应用程序中使用过它,该应用程序需要通过反射重复访问属性(因为在编译时无法知道属性名)。

通过在运行时创建一个帮助类来生成访问属性的代码,生成的代码比原始的仅反射代码快上数量级。


我刚刚写了一个库来完成这个任务,但它使用的是“表达式树”而不是“反射.Emit”。 - Gabe

2
XMLSerializer实际上会在第一次运行时生成代码并进行编译。如果您知道这种情况正在发生,可以阅读Scott Hanselman网站上的这篇优秀博客文章,了解如何调试XML序列化。请注意保留HTML标签。

1
该帖子建议XMLSerializer实际上生成C#代码并编译它,而不是直接发出IL。 - Daniel Brückner

2

模拟库也使用Reflection.Emit生成在单元测试中使用的代理。


2
  1. 生成声明式代码,例如使用接口声明基础HTTP REST服务。https://github.com/neurospeech/retro-core-fit

  2. 性能增强器,大部分时间我使用 Expression.Compile 创建代码片段,通过编译给定表达式来快速检索信息,以便在将来执行编译的委托。如果使用 PropertyInfo.GetValue,它会非常慢,但是如果创建一个访问属性的表达式并将其编译为委托(内部使用Reflection.Emit),则可以节省大量CPU时间。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接