Как я могу отправить выражение System.Linq.Expression? - PullRequest
16 голосов
/ 27 февраля 2010

У меня есть некоторый код, который генерирует различные Func<> делегаты, используя System.Linq.Expressions и Expression.Lambda<Func<>>.Compile() и т. Д. Я хотел бы иметь возможность сериализовать сгенерированные функции в сборку для последующего использования. В прошлом я кое-что делал с System.Reflection.Emit, но теперь, когда в выражениях Linq я бы больше не хотел идти этим путем.

Существует ли механизм для сериализации скомпилированного выражения или какой-то мост из пространства имен Expressions в пространство имен Emit?

Редактировать

Некоторый фон для контекста: Я работаю над механизмом запросов (в основном для собственного назидания и удовольствия). Учитывая оператор SQL, я хотел бы проанализировать и преобразовать его в лямбда-функцию, а затем сериализовать на диск для последующего (и повторного выполнения).

В псевдокоде я нахожусь к этому пункту:

Func<IEnumerable<T>, IEnumerable<T1>> query = Query.Parse<T, T1>("Select field AS A, field1 AS B from T where T.field2 > 5");

(где field , field1 и field2 являются свойствами Тип T и A и B являются свойствами Тип T1 . и я могу передать любое перечисление от <T> до query и получить обратно и перечисление <T1>, которое соответствует критериям запроса.

Так что я бы хотел сериализовать query на диск как уже скомпилированную сборку, чтобы позже я мог загрузить его и оценить различные наборы <T> без разбора и компиляции. Я представляю что-то вроде:

AssemblyBuilder builder = new AssemblyBuilder(...);
ModuleBuilder module = builder.DefineDynamicModule(...);
TypeBuilder type = module.DefineType(...);
type.AddMethod(query);  // <--- where this piece does not exist as far as I know
builder.Emit(...)

Ответы [ 3 ]

3 голосов
/ 27 февраля 2010

Я не думаю, что есть способ сделать это. В конце концов, Expression может захватывать произвольные значения времени выполнения, которые нельзя сериализовать в сборку.

Казалось бы, вы могли бы обойти это, вызвав expr.Compile().Method.GetMethodBody().GetILAsByteArray(), чтобы получить IL как байты, которые затем могли бы быть записаны в MethodBuilder в сборке, которую вы могли бы затем записать в файл. К сожалению, это не сработает - вызов GetMethodBody() завершится неудачно, потому что делегат динамический.

3 голосов
/ 15 декабря 2012

LambdaExpression имеет метод CompileToMethod , который предназначен для MethodBuilder. Используя это и Reflection.Emit, вы сможете создать класс и записать его в сборку.

3 голосов
/ 27 февраля 2010

Я не уверен, что именно ваша большая картинка, но, глядя чисто на ваш второй абзац, вы можете написать чистый код на основе Expression, собрать его, а затем открыть свою сборку в Reflector, используя языковой надстройку Reflection.Emit. в. Этот фрагмент мета-мета-хитрости покажет вам операторы Reflection.Emit, необходимые для динамической генерации вашего Expression / Lambda-кода.

-Oisin

...