Подтвердить что ты не робот

Как я могу испустить выражение System.Linq.Expression?

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

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

Edit

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

В псевдокоде я к этому моменту:

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

(где поле, поле1 и поле2 - это свойства типа 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(...)
4b9b3361

Ответ 1

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

-Oisin

Ответ 2

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

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

Ответ 3

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