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.
Reflection. Emit is a powerful namespace in which we can dynamically emit transient and persisting assemblies at runtime. Reflection. Emit produces a low-level, language-neutral MSIL. Normally, we create an assembly by saving its source code to disk and then compiling that source code.
The CodeDOM provides types that represent many common types of source code elements. You can design a program that builds a source code model using CodeDOM elements to assemble an object graph. This object graph can be rendered as source code using a CodeDOM code generator for a supported programming language.
Reflection provides objects that encapsulate assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object. You can then invoke the type's methods or access its fields and properties.
Yes, it is.
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 using Expression
). For some scenarios you also may not really need a full class hierarchy - often a dictionary of dynamically generated delegates such as Dictionary<string, Action>
could be good enough (but of course, it depends on your exact scenario).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With