Where is the "code as data" in the DLR expression?

I have a C # code:

Console.Writeline("Hello World"); 

If I want to do this with a DLR expression, it looks something like this:

 MethodInfo method = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) }); Expression callExpression = Expression.Call(null, method, Expression.Constant("Hello World")); Action callDelegate = Expression.Lambda<Action>(callExpression).Compile(); callDelegate(); 

I took this example from the Pro DLR book in .NET 4. And I don’t understand why we are doing this extra work? The book says that the reason is that once the code is represented as objects in memory, it is much easier to parse than the IL instruction.

Which confuses me more: If I put the DLR expression instead of the ConsoleWriteline () method in my code and run the console applicator, I get the same .exe file (which contains the CIL code), and as a result I get "Hello world" written on the console . exe executable file. Therefore, in both cases, I get the executable .exe file (cil code) and I don’t see where the objects that represent the code as data at runtime are located , and how can I access them?

+4
source share
3 answers

Basically, the second code fragment encapsulates a call as an expression tree. Expression trees are relatively new to .NET (they were necessary to implement Linq interaction with data mechanisms other than objects in memory) and encapsulate program instructions in a modifiable but still executable form.

If you wanted, as soon as you get this expression, you can change the text that will be output from "Hello World" to "Hello Dolly" by changing the value of the node constant referenced by the node call. You can modify the node call to use another MethodInfo, for example, the call to Debug.WriteLine () or the native WriteToLog () method that you are developing. You can also pass this expression around, save it, serialize it, and call it much further than this simple example. All of these changes and decisions can be made at runtime based on information that is unknown at compile time. A dynamically constructed expression tree can be created based on data in a file or database, which is easy to modify and does not require the release of a new version of a DLL or EXE containing this string.

In contrast, the “static” call to Console.WriteLine () can only be changed at compile time (despite the possibility of some VERY promiscuous IL-emitting dynamic code), requiring such a change if the requirements are for where this line is written with change.

+3
source

I don’t see where these objects which represents the code as data at runtime and how can I access them?

This is Expression , which represents code as data: it is a call to the Console.WriteLine method with "Hello World " as the only argument.

Here is an example of detecting this fact at runtime:

 var method = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(String) }); var callExpression = Expression.Call(null, method, Expression.Constant("Hello World")); var expression = Expression.Lambda<Action>(callExpression); // Now let try to inspect 'expression' var body = expression.Body as MethodCallExpression; if (body != null) { Console.WriteLine("Expn body is a method-call expn."); Console.WriteLine("...that calls:" + body.Method.Name); var args = body.Arguments; if (args.Any()) { Console.WriteLine("The call has arguments."); var firstArg = args.First() as ConstantExpression; if (firstArg != null) { Console.WriteLine("The first argument is a constant expn."); Console.WriteLine("...with value " + firstArg.Value); } } } 
+1
source

As an aside, another way of generating an expression is:

 Expression<Action> e=()=>Console.WriteLine("Hello World"); 

This eliminates the need to write reflection code.

+1
source

Source: https://habr.com/ru/post/1344131/


All Articles