Reflection.Emit与CodeDOM
使用Reflection.Emit库与CodeDOM在运行时dynamic生成代码有什么优点/缺点?
我正试图在一个系统中生成一些(相对复杂的)dynamic类,这些类是基于运行时可用的XML格式的元数据。 我将生成扩展应用程序集合中的现有类,实现更多接口,添加方法以及覆盖虚拟和抽象成员的类。
在深入实施之前,我想确保select合适的技术。 有关这些不同的代码生成技术如何不同的任何信息将会有所帮助。 此外,任何关于简化或简化工作的开放源代码库的信息都会有用。
我认为关于CodeDOM和Reflection.Emit的关键点如下:
-
CodeDom生成C#源代码,通常用于生成代码作为解决scheme的一部分,并在IDE中进行编译(例如,LINQ to SQL类,WSDL,XSD都以这种方式工作)。 在这种情况下,您也可以使用部分类来自定义生成的代码。 效率不高,因为它生成C#源代码,然后运行编译器parsing(再次!)并编译它。 您可以使用相对较高级别的构造(类似于C#expression式和语句)来生成代码,如循环。
-
Reflection.Emit生成一个IL,因此直接生成一个只能存储在内存中的程序集。 结果是效率更高。您必须生成低级IL代码(值存储在堆栈中;循环必须使用跳转来实现),因此生成更复杂的逻辑有点困难。
一般来说,我认为Reflection.Emit通常被认为是在运行时生成代码的首选方式,而在编译时生成代码时首选CodeDOM。 在你的场景中,他们都可能工作正常(虽然CodeDOM可能需要更高的权限,因为它实际上需要调用C#编译器,这是任何.NET安装的一部分)。
另一种select是使用Expression
类 。 在.NET 4.0中,它允许您生成等效于C#expression式和语句的代码。 但是,它不允许你生成一个类。 所以,你可以把它和Reflection.Emit结合起来(用来生成将实现委托给使用Expression
生成的代码的类)。 对于一些场景,你也可能不需要完整的类层次结构 – 通常dynamic生成的委托(如Dictionary<string, Action>
可能足够好(但当然,这取决于你的确切场景)。
以CodeDom为目标的代码往往容易维护,因为你正在生成C#代码而不是IL(更多的人可以阅读C#而不是IL)。 此外,如果您的CodeDom代码错误,则会出现编译器错误; 如果生成无效的IL,则会发生致命exception或崩溃。
但是,由于CodeDom调用了csc.exe
编译器,所以使代码准备就绪稍慢一些。 使用Reflection.Emit,您可以直接在内存中生成代码。
CodeDom对于大多数情况来说可能是很好的。 XmlSerializer
和WinFormsdevise器使用它。
你可能想看看ExpandoObject
。 但是它只是.NET 4.0。