Есть ли простой способ разбора строки (лямбда-выражения) в делетете Action?
У меня есть метод, который изменяет объект "Учетная запись" на основе переданного ему делегата действия:
public static void AlterAccount(string AccountID, Action<Account> AccountAction) {
Account someAccount = accountRepository.GetAccount(AccountID);
AccountAction.Invoke(someAccount);
someAccount.Save();
}
Это работает по назначению...
AlterAccount("Account1234", a => a.Enabled = false);
... но теперь то, что я хотел бы попробовать, это иметь такой способ:
public static void AlterAccount(string AccountID, string AccountActionText) {
Account someAccount = accountRepository.GetAccount(AccountID);
Action<Account> AccountAction = MagicLibrary.ConvertMagically<Action<Account>>(AccountActionText);
AccountAction.Invoke(someAccount);
someAccount.Save();
}
Затем его можно использовать как:
AlterAccount("Account1234", "a => a.Enabled = false");
отключить учетную запись "Account1234".
Я просмотрел динамическую библиотеку запросов linq, которая, кажется, делает больше или меньше того, что я хочу, но для делегатов типа Func, и мои знания деревьев выражений и т.д. недостаточно хороши, чтобы понять, как добиться того, чего я хочу.
Есть ли простой способ сделать то, что я хочу, или мне нужно правильно изучить выражения и написать нагрузку кода?
(Причина, по которой я хочу сделать это, - это простой способ массового обновления объектов учетной записи из powershell script, где пользователь может указать lambda-выражение для выполнения изменений.)
Ответы
Ответ 1
Библиотека Dynamic LINQ является прекрасным выбором, так как она будет генерировать выражения, которые вы можете легко компилировать в код.
Пример, который вы предоставили, фактически создает логическое значение - поэтому вы должны иметь возможность запросить Func, и он может его отсортировать.
Изменить: это, конечно, неправильно, поскольку у выражений вообще нет задания.
Итак, еще один потенциальный способ - взять два лямбда. Один, чтобы найти нужное свойство, чтобы обеспечить значение:
(a = > a.AccountId), (a = > true)
Затем используйте отражение, чтобы установить свойство, указанное в первой лямбда, с результатом второго. Hackish, но он все же, вероятно, облегчен по сравнению с вызовом компилятора С#.
Таким образом, вам не нужно делать много кодегенов самостоятельно - выражения, которые вы получите, будут содержать больше всего, что вам нужно.
Ответ 2
Вы можете попробовать следующее: Динамические выражения лямбда с использованием изолированного AppDomain
Он компилирует лямбда-выражение с использованием компилятора CodeDOM. Чтобы избавиться от сборки в памяти, которая создается, компилятор работает с изолированным AppDomain
. Для передачи выражения через границу домена он должен быть сериализован. Увы, Expression<>
не Serializable
. Итак, нужно использовать трюк. Все подробности объясняются в сообщении.
Я, кстати, автор этого компонента. Я бы очень хотел услышать ваши отзывы.
Ответ 3
Нет общего способа синтаксического анализа строки в выражении лямбда без полной компиляции, потому что лямбда-выражения могут ссылаться на вещи, которые определены вне выражения лямбда. Я не знаю никакой библиотеки, которая обрабатывает конкретный случай, который вы хотите. Там долго обсуждалось это в thread в группе обсуждения С#.
Самый простой способ получить то, что вы хотите, - это скомпилировать метод во время выполнения. Вы можете написать функцию, которая принимает строку "a.Enabled = true; return a;" и указывает, что в середине функции, которая принимает учетную запись в качестве параметра. Я бы использовал эту библиотеку в качестве отправной точки, но вы также можете использовать функцию, упомянутую в другой нить.
Ответ 4
Вы можете использовать Spring.NET механизм оценки выражения лямбда
Выражение может быть немного иным, но все же вы будете использовать выражение String для выражения.
Ответ 5
Это легко:
- Используйте CodeDom для создания модуля, содержащего "окружающий класс", который вы будете использовать для построения выражения; этот класс должен реализовать интерфейс, известный вашему приложению
- Используйте CodeSnippedExpression, чтобы вставить выражение в его член.
- Используйте Activator, чтобы создать экземпляр этого класса во время выполнения.
В принципе, вам нужно построить следующий класс с CodeDom:
using System;
using MyNamespace1;
using ...
using MyNamespace[N];
namespace MyNamespace.GeneratedTypes
{
public class ExpressionContainer[M] : IHasAccountAction
{
public Action<Account> AccountAction {
get {
return [CodeSnippedExpression must be used here];
}
}
}
}
Предполагая, что IHasAccountAction
:
public IHasAccountAction {
public Action<Account> AccountAction { get; }
}
Если это будет сделано, вы можете легко скомпилировать выражение, скомпилированное из строки. Если вам нужно представление дерева выражений, используйте Expression<Action<Account>>
вместо Action<Account>
в сгенерированном типе.
Ответ 6
Вы можете попробовать один из этих парсеров выражения лямбда:
http://simproexpr.codeplex.com
http://www.codeproject.com/Tips/320127/Execute-lambda-expression-given-as-string