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

Есть ли простой способ разбора строки (лямбда-выражения) в делетете 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-выражение для выполнения изменений.)

4b9b3361

Ответ 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> в сгенерированном типе.