When can the System.Reflection.Emit namespace come in handy?
It seems that in .NET classes are provided that allow you to generate dynamically assemblies in a high-level language.
Why dive low?
When can the System.Reflection.Emit namespace come in handy?
It seems that in .NET classes are provided that allow you to generate dynamically assemblies in a high-level language.
Why dive low?
Reflection.Emit is for those who want to create dynamic assemblies (and not add something to existing ones) on pure IL (hardcore is shorter). More details below.
If you just need a dynamic type, maybe you just need dynamic or ExpandoObject ? And no code generation, the truth about the verification at the compilation stage can be forgotten.
Do you need a method (can also their group) that will accept and analyze lambda expressions? Then use Expression Trees. For simple cases it will be good, but if you decided to write your ORM, then this occupation is not at all simple. Remember that for Expression Trees, only single-line lambda expressions are supported.
If you need dynamically generated HTML (suddenly), and this is not a web application, then use RazorEngine . Also by simulating a web application, you can add support for Intellisense.
In short: if you still need full code generation, use Roslyn. Because it is powerful and platform independent. T4 may also be useful (especially if you need non-C # and non-VB code).
Reflection.EmitBenefits
Microsoft.CodeDom , but Roslyn is fine, because it pulls the compiler as a service).Microsoft.CodeDom , which is specific only to the Microsoft implementation, but Roslyn is also platform-independent)disadvantages
Reflection.Emit .Based on this, decide whether you want to use Reflection.Emit or not. But I suppose it's quite hardcore.
Microsoft.CodeDomMicrosoft.CodeDom vs Reflection.EmitThe generated code using Microsoft.CodeDom can be part of the solution (LINQ to SQL, WSDL, XSD classes are generated in this way). You can also use partial classes to tweak generated code. When using Reflection.Emit you are required to create a new assembly.
When you use Reflecion.Emit you program with IL commands. When you program with Microsoft.CodeDom you create C # commands.
Therefore Microsoft.CodeDom will be easier to create Microsoft.CodeDom code, as you program with higher level commands. The code created on Reflecion.Emit will be more difficult to create on IL (for example, cycles will have to be created using transitions), especially when you program complex logic.
From this it follows that there are more opportunities on Reflection.Emit (so IL has more opportunities than C #). However, for every familiar thing in C #, you will have to write a lot more code.
The Microsoft.CodeDom code will be slower than Reflection.Emit , since it is compiled, then the C # code is generated, then this generated code is compiled. Reflection.Emit immediately compiled into an assembly.
As @Grundy correctly noted, this is platform independence for Reflecion.Emit . And Microsoft.CodeDom is available only on Microsoft platforms.
However, I would not use Microsoft.CodeDom . For Roslyn is more powerful and expressive.
Microsoft.CodeDom not just a wrapper on csc.exe, but can also analyze the code semantically, dynamically compile and parse the code. This is a way to create any tool for C # and VB. Therefore, there are possibilities from formatting the code to finding all the references in the solution for a given symbol.But what if you do not need a dynamically generated assembly, but need to supplement part of an existing solution?
Or if you need dynamically generated files, but not C # or VB? For example, say JavaScript or CSS. (For HTML, I recommend RazorEngine if that, but using T4 is also possible). Or some kind of exotic expansion. And yet, having aggravated the task, there are several of these files, but the number is known only at the time the code is executed.
Then you can use T4. This is a tool in Visual Studio (or just a console utility ) that is used to generate code for any language. Also available in MonoDevelop.
At once I will say that the Entity Framework (not. NET Core) uses T4.
Conceptually similar to ASPX, only code between C # -insert <# #> not necessarily HTML / CSS / JavaScript, but in the programming language of the target file. Manuals .
Of the minuses
As already mentioned in the previous answer, there are several ways of code generation. Some of them allow you to generate code in design time, i.e. in IDE (T4). The other is to generate C # code at runtime (CodeDom), and the third is to generate executable code (ie, IL) at runtime (Reflection.Emit).
And although it may seem that the latter case is quite rare, it is not. Without even thinking, you use this business all the time.
Yes, if you create a regular expression as follows: var regex = new Regex("abc", RegexOptions.Compiled); , the runtime will generate a class with a specialized state machine using Reflection.Emit, and will not interpret the regular expression each time.
Yes, most serializers use reflection, but this is a very slow thing. Therefore, the same XmlSerializer will generate a special class of the serializer during execution and save it in a special folder for later use. The same approach is also used by the binary serializer, and Newtonsoft.Json, beloved by everyone, does not shy away from code generation.
For example, we want to make a run-time decorator for logging. If we have a virtual method marked with the [LogMethod] attribute, then we can generate a class of an heir that will override this virtual method and log all method arguments, and then call the base implementation.
PostSharp and other AOP frameworks are built directly on the technology of code generation during execution.
Yes, Expression Trees in C # is a high-level construct, but the Expression.Compile method actually uses Reflection.Emit to generate code at runtime.
Any Automappers use Reflection.Emit to generate a match between the display of instances of one type to another.
This is a special case of mappers and they use code generation in full. NHibernate, LINQ 2 SQL, Entity Fraework, all generate classes at runtime to map objects to each other or to intercept calls to the repository method.
Rhyno Mocks, Moq and others, all of them are based either on Expression Trees or directly on Reflection.Emit (yes, many mock frameworks use DynamicProxy, which already uses Reflection.Emit) to generate stubs for testing.
Yes, and they also generate various proxy classes for call inspection and other instrumentation during execution.
And again, in order to make the logging process as simple as possible, code generation is used in such tools.
The CLR has special functionality for interacting with dynamically typed languages, such as Python, Ruby etc. There, DLR is used to its fullest to increase productivity.
You will not believe it, but you can use Reflection.Emit (albeit indirectly) even to bypass the standard problems of the C # language.
Perhaps you know that the new T() restriction for generics is fear and horror. It uses reflection, which seriously affects performance, and it also wraps up exceptions that occurred when creating an instance in TargetInvocationException . I have already encountered in several projects that this method essentially spoils the end-to-end execution time. Therefore, these projects use a specialized CustomActivactor :
public static class CustomActivator { public static T CreateInstance<T>() where T : new() { return ActivatorImpl<T>.Factory(); } private class ActivatorImpl<T> where T : new() { // Под колпаком используем Reflection.Emit! private static readonly System.Linq.Expressions.Expression<Func<T>> _expr = () => new T(); public static readonly Func<T> Factory = _expr.Compile(); } } Now our activator does not suffer from performance problems and does not wrap exceptions from constructors into a boring TargetInvocationExpression .
ZY Actually, I touched only part of the scripts, the same ASP.NET uses code generation to the fullest. To understand the full picture, you can try to search for yourself. For example, you can search for the ILGenerator type or something else from the System.Reflection.Emit namespace:
ILGenerator (there is no semantic search there, so many links will not be valid, but will make it clear the scale of the tragedy).UPDATE: this topic has resulted in a rather long post on the subtleties of the work of the activator, generalizations and code generation - Dissecting the new () constraint in C #: a perfect example of a leaky abstraction .
expression.Compie() , then the inner class can be omitted? - Grundynew() constraint is not necessary, is it? - GrundySource: https://ru.stackoverflow.com/questions/607803/
All Articles