Замена параметров в лямбда-выражении

У меня была часть кода, который берет в лямбда-выражениях при времени выполнения, которое я могу затем скомпилировать и вызвать.

Something thing;

Expression<Action<Something>> expression = (c => c.DoWork());
Delegate del = expression.Compile();
del.DynamicInvoke(thing);

Для сохранения времени выполнения я сохранил тех скомпилированных делегатов в кэше, a Dictionary<String, Delegate> который ключ является строкой лямбда-выражения.

cache.Add("(Something)c => c.DoWork()", del);

Для точно тех же самых вызовов это хорошо работало. Однако я понял, что мог получить эквивалентные лямбды, такой как "d => d. DoWork ()", который я должен на самом деле использовать того же делегата к, и я не был.

Это получило меня задающийся вопросом, был ли очевидный способ (чтение, "не использующее Строку. Замена", я уже сделал это как временное приспособление) заменять элементы в лямбда-выражении, как, возможно, замена их arg0 так, чтобы оба

(c => c.DoWork()) и (d => d.DoWork())

преобразованы и сравнены как (arg0 => arg0.DoWork()) при помощи чего-то fuctionnally подобного введению Выражения. Параметр (Тип, Имя) в лямбде.

Это возможно? (Ответы могут включать C#4.0),

6
задан Dynami Le Savard 20 January 2010 в 19:59
поделиться

2 ответа

Я использовал струны, так как это был легкий путь для меня. Вы не можете вручную изменить имя выражения параметра (имеет свойство «Имя», но это только для чтения), поэтому вы должны построить новое выражение от кусочков. То, что я сделал, создан «безымянным» параметром (на самом деле, он получает автогенерацию в этом случае, который является «PARAM_0»), а затем создал новое выражение почти так же, как старый, но используя новый параметр.

public static void Main()
{
    String thing = "test";

    Expression<Action<String>> expression = c => c.ToUpper();
    Delegate del = expression.Compile();
    del.DynamicInvoke(thing);

    Dictionary<String, Delegate> cache = new Dictionary<String, Delegate>();
    cache.Add(GenerateKey(expression), del);

    Expression<Action<String>> expression1 = d => d.ToUpper();
    var test = cache.ContainsKey(GenerateKey(expression1));
    Console.WriteLine(test);

}

public static string GenerateKey(Expression<Action<String>> expr)
{
    ParameterExpression newParam = Expression.Parameter(expr.Parameters[0].Type);
    Expression newExprBody = Expression.Call(newParam, ((MethodCallExpression)expr.Body).Method);
    Expression<Action<String>> newExpr = Expression.Lambda<Action<String>>(newExprBody, newParam);
    return newExpr.ToString();
}
3
ответ дан 17 December 2019 в 02:29
поделиться

Есть больше для выражения лямбда, чем просто текст. Лямбдас переписан компилятором на что-то гораздо сложное. Например, они могут закрыть переменные (которые могут включать другие делегаты). Это означает, что два лямбдас могут выглядеть точно так же, но выполнять совершенно разные действия.

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

3
ответ дан 17 December 2019 в 02:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: