Reflection.Emit 与 CodeDOM
使用 Reflection.Emit 库与 CodeDOM 在运行时动态生成代码相比,有哪些优缺点?
我正在尝试根据运行时可用的元数据在系统中生成一些(相对复杂的)动态类XML 形式。我将生成扩展应用程序程序集中现有类的类、实现附加接口、添加方法以及重写虚拟和抽象成员。
我想确保在深入实施之前选择合适的技术。任何有关这些不同的代码生成技术有何不同的信息都会有所帮助。此外,有关简化或简化使用任一 API 的工作的开源库的任何信息也将很有用。
What are some pros/cons for using the Reflection.Emit library versus CodeDOM for dynamically generating code at runtime?
I am trying to generate some (relatively complicated) dynamic classes in a system based on metadata available at runtime in XML form. I will be generating classes that extend existing classes in the application assembly, implementing additional interfaces, adding methods, and overriding virtual and abstract members.
I want to make sure I select the appropriate technique before I get too deep into the implementation. Any information about how these different code-generation techniques differ would be helpful. Also, any information on open-source libraries that simplify or streamline working wither either API would be useful as well.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为 CodeDOM 和 Reflection.Emit 的关键点如下:
CodeDom 生成 C# 源代码,通常在生成要作为解决方案的一部分包含并在 IDE 中编译的代码时使用(例如,LINQ to SQL 类、WSDL、XSD 都以这种方式工作)。在这种情况下,您还可以使用分部类来自定义生成的代码。它的效率较低,因为它生成 C# 源代码,然后运行编译器来解析它(再次!)并编译它。您可以使用相对高级的构造(类似于 C# 表达式和语句)(例如循环)生成代码。
Reflection.Emit 生成一个 IL,因此它可以直接生成一个也只能存储在内存中的程序集。因此效率要高得多。您必须生成低级 IL 代码(值存储在堆栈上;循环必须使用跳转来实现),因此生成任何更复杂的逻辑都有点困难。
总的来说,我认为 Reflection.Emit 通常被认为是运行时生成代码的首选方式,而 CodeDOM 是编译前生成代码时的首选方式。在您的场景中,它们可能都可以正常工作(尽管 CodeDOM 可能需要更高的权限,因为它实际上需要调用 C# 编译器,这是任何 .NET 安装的一部分)。
另一种选择是使用 <代码>表达式类。在 .NET 4.0 中,它允许您生成与 C# 表达式和语句等效的代码。但是,它不允许您生成类。因此,您可以将其与 Reflection.Emit 结合起来(生成将实现委托给使用
Expression
生成的代码的类)。对于某些场景,您可能并不真正需要完整的类层次结构 - 通常动态生成的委托的字典(例如Dictionary
可能就足够了(但当然,这取决于您的具体情况)设想)。I think the key points about CodeDOM and Reflection.Emit are following:
CodeDom generates C# source code and is usually used when generating code to be included as part of a solution and compiled in the IDE (for example, LINQ to SQL classes, WSDL, XSD all work this way). In this scenario you can also use partial classes to customize the generated code. It is less efficient, because it generates C# source and then runs the compiler to parse it (again!) and compile it. You can generate code using relatively high-level constructs (similar to C# expressions & statements) such as loops.
Reflection.Emit generates an IL so it directly produces an assembly that can be also stored only in memory. As a result is a lot more efficient.You have to generate low-level IL code (values are stored on stack; looping has to be implemented using jumps), so generating any more complicated logic is a bit difficult.
In general, I think that Reflection.Emit is usually considered as the preferred way to generate code at runtime, while CodeDOM is preferred when generating code before compile-time. In your scenario, both of them would probably work fine (though CodeDOM may need higher-privileges, because it actually needs to invoke C# compiler, which is a part of any .NET installation).
Another option would be to use the
Expression
class. In .NET 4.0 it allows you to generate code equivalent to C# expressions and statements. However, it doesn't allow you to generate a classes. So, you may be able to combine this with Reflection.Emit (to generate classes that delegate implementation to code generated usingExpression
). For some scenarios you also may not really need a full class hierarchy - often a dictionary of dynamically generated delegates such asDictionary<string, Action>
could be good enough (but of course, it depends on your exact scenario).针对 CodeDom 的代码往往更容易维护,因为您生成的是 C# 代码而不是 IL(能够阅读 C# 的人比能够阅读 IL 的人多)。此外,如果 CodeDom 代码错误,则会出现编译器错误;如果生成无效的 IL,则会出现致命异常或崩溃。
但是,由于 CodeDom 调用
csc.exe
编译器,因此准备使用代码的速度会稍慢一些。使用Reflection.Emit,您可以将代码直接生成到内存中。CodeDom 可能适合大多数事情;
XmlSerializer
和 WinForms 设计器使用它。Code that targets CodeDom tends to be easier to maintain, since you're generating C# code and not IL (more people can read C# than IL). Futhermore, if you get your CodeDom code wrong, you get a compiler error; if you generate invalid IL, you get a fatal exception or a crash.
However, because CodeDom invokes the
csc.exe
compiler, it's a little slower to get the code ready for use. With Reflection.Emit, you can generate code directly into memory.CodeDom is probably fine for most things; the
XmlSerializer
and the WinForms designer use it.您可能想查看
ExpandoObject
。然而它只是.NET 4.0。You might want to look at
ExpandoObject
. However it's .NET 4.0 only.