52

使用 Reflection.Emit 库与 CodeDOM 在运行时动态生成代码有哪些优点/缺点?

我正在尝试根据运行时以 XML 形式提供的元数据在系统中生成一些(相对复杂的)动态类。我将生成扩展应用程序集中现有类的类,实现额外的接口,添加方法,并覆盖虚拟和抽象成员。

我想确保在深入实施之前选择合适的技术。有关这些不同代码生成技术有何不同的任何信息都会有所帮助。此外,任何有关简化或简化使用任一 API 的开源库的信息也将很有用。

4

3 回答 3

66

我认为 CodeDOM 和 Reflection.Emit 的关键点如下:

  • CodeDom生成 C# 源代码,通常在生成要包含在解决方案中并在 IDE 中编译的代码时使用(例如,LINQ to SQL 类、WSDL、XSD 都以这种方式工作)。在这种情况下,您还可以使用部分类来自定义生成的代码。它的效率较低,因为它生成 C# 源代码,然后运行编译器来解析它(再次!)并编译它。您可以使用循环等相对高级的构造(类似于 C# 表达式和语句)生成代码。

  • Reflection.Emit生成一个 IL,因此它直接生成一个程序集,该程序集也只能存储在内存中。因此效率更高。您必须生成低级 IL 代码(值存储在堆栈中;必须使用跳转来实现循环),因此生成任何更复杂的逻辑有点困难。

总的来说,我认为 Reflection.Emit 通常被认为是在运行时生成代码的首选方式,而在编译时生成代码时首选 CodeDOM。在您的场景中,它们可能都可以正常工作(尽管 CodeDOM 可能需要更高的权限,因为它实际上需要调用 C# 编译器,这是任何 .NET 安装的一部分)。

另一种选择是使用Expression。在 .NET 4.0 中,它允许您生成与 C# 表达式和语句等效的代码。但是,它不允许您生成类。因此,您可以将其与 Reflection.Emit 结合使用(以生成将实现委托给使用生成的代码的类Expression)。对于某些场景,您可能也不需要完整的类层次结构——通常是动态生成的委托的字典,例如Dictionary<string, Action>可能就足够了(但当然,这取决于您的具体场景)。

于 2010-03-02T22:54:43.930 回答
17

以 CodeDom 为目标的代码往往更易于维护,因为您生成的是 C# 代码而不是 IL(更多的人可以阅读 C# 而不是 IL)。此外,如果你的 CodeDom 代码错误,你会得到一个编译器错误;如果生成无效的 IL,则会出现致命异常或崩溃。

但是,因为 CodeDom 调用csc.exe编译器,所以让代码准备好使用会稍微慢一些。使用 Reflection.Emit,您可以将代码直接生成到内存中。

CodeDom 可能适用于大多数事情。和XmlSerializerWinForms 设计器使用它。

于 2010-03-02T22:56:42.043 回答
7

你可能想看看ExpandoObject. 但是它只是 .NET 4.0。

于 2010-03-02T21:35:08.240 回答