Где находится «код как данные» в выражении DLR? - PullRequest
4 голосов
/ 17 марта 2011

У меня есть этот код c #:

Console.Writeline("Hello World");

Если я хочу сделать это с выражением DLR, оно выглядит примерно так:

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();

Я взял этот пример из книги Pro DLR в .NET 4. И я не понимаю, почему мы делаем эту дополнительную работу? Книга говорит, что причина в том, что как только код представлен в виде объектов в памяти, его гораздо легче проанализировать, чем инструкцию IL.

Что меня больше всего смущает: Если я добавлю выражение DLR вместо метода ConsoleWriteline () в своем коде и запусту приложение консоли, я получу тот же файл .exe (который содержит код CIL), и в результате я получу «Hello world», записанный в консоли. исполняемый файл. Таким образом, в обоих случаях я получаю исполняемый файл .exe (cil-код), и Я не вижу, где находятся эти объекты, представляющие код в виде данных во время выполнения и как я могу получить к ним доступ?

Ответы [ 3 ]

3 голосов
/ 17 марта 2011

По сути, второй фрагмент кода инкапсулирует вызов в виде дерева выражений.Деревья выражений являются относительно новыми для .NET (они были необходимы для реализации взаимодействия Linq с механизмами данных, отличными от объектов в памяти), и инкапсулируют программные инструкции в изменяемой, но все еще исполняемой форме.

Если вы хотите,получив выражение, вы можете изменить текст для вывода из «Hello World» на «Hello Dolly», изменив значение узла Constant, на который ссылается узел Call.Вы можете изменить узел Call, чтобы использовать другой MethodInfo, например, вызов Debug.WriteLine () или пользовательский метод WriteToLog (), который вы разрабатываете.Вы также можете передать это выражение, сохранить его, сериализовать и вызвать его гораздо дальше, чем в этом простом примере.Все эти изменения и решения могут быть приняты во время выполнения на основе информации, которая не известна во время компиляции.Динамически построенное дерево выражений может быть создано на основе данных в файле или базе данных, которое легко изменить и не требует выпуска новой версии DLL или EXE-файла, содержащего эту строку.

В отличие от этого«статический» вызов Console.WriteLine () может быть изменен только во время компиляции (несмотря на возможность какого-либо ОЧЕНЬ грязного динамического кода, генерирующего IL), требуя такого изменения, если изменяются требования к месту записи этой строки.

1 голос
/ 21 марта 2011

Кроме того, еще один способ генерирования выражения:

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

Это избавит вас от необходимости писать стандартный код отражения.

1 голос
/ 17 марта 2011

Я не вижу, где находятся те объекты, которые представляют код как данные во время выполнения и как я могу получить к ним доступ?

Это Expression, который представляет код в виде данных:он представляет собой вызов метода Console.WriteLine с "Hello World "в качестве единственного аргумента.

Вот пример обнаружения этого факта во время выполнения:

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's try to inspect 'expression'

var body = expression.Body as MethodCallExpression;

if (body != null)
{
    Console.WriteLine("Expn's 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);
        }
    }
}
...