Можно ли привести экземпляр делегата в лямбда-выражение? - PullRequest
0 голосов
/ 21 января 2009

Вот контекст для моего вопроса:

Обычный способ - объявить параметр метода как лямбда-выражение, а не как делегат. Это сделано для того, чтобы метод мог исследовать выражение, чтобы делать интересные вещи, такие как поиск имен вызовов метода в теле экземпляра делегата.

Проблема заключается в том, что вы теряете некоторые интеллектуальные свойства Resharper. Если параметр метода был объявлен как делегат, Resharper выручил бы при написании вызова этого метода, предложив вам использовать синтаксис x => x для предоставления в качестве значения аргумента этому методу.

Итак ... вернемся к моему вопросу. Я хотел бы сделать следующее:

    MethodThatTakesDelegate(s => s.Length);
}

private void MethodThatTakesDelegate(Func<string, object> func)
{
    //convert func into expression
    //Expression<Func<string, object>> expr = "code I need to write"

    MethodThatTakesExpression(expr);
}


private void MethodThatTakesExpression(Expression<Func<string, object>> expr)
{
    //code here to determine the name of the property called against string (ie the Length)
}

Ответы [ 3 ]

2 голосов
/ 21 января 2009

Везде, где вы используете термин «лямбда-выражение», вы на самом деле имеете в виду «дерево выражений».

Лямбда-выражение - это бит в исходном коде, который

parameters => code

, например

x => x * 2

Деревья выражений являются экземплярами класса System.Linq.Expressions.Expression (или, скорее, одного из производных классов), которые представляют код как данные.

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

Вы можете скомпилировать экземпляр LambdaExpression (который является одним из подклассов Expression) в делегат, но вы не можете перейти наоборот.

Теоретически может быть возможным написать такой "декомпилятор" на основе IL, возвращенного MethodBase.GetMethodBody в некоторых ситуациях, но в настоящее время существует различные делегаты, которые не могут быть представлены деревьями выражений. Дерево выражений представляет выражение , а не оператор или блок операторов - так что нет никаких циклов, ветвлений (кроме условных), присваивания и т. Д. Я считаю, что это может измениться в .NET 4.0, хотя я не ожидаю от Microsoft декомпиляции, если для этого нет веских причин.

0 голосов
/ 21 января 2009

Нет, это невозможно.

0 голосов
/ 21 января 2009

Я не верю, что здесь можно достичь того, чего вы хотели бы. Из комментариев в вашем коде похоже, что вы пытаетесь захватить имя свойства, которое выполнило присвоение в MethodThatTakesExpression. Для этого требуется лямбда-выражение дерева выражений, которое фиксирует контекст доступа к свойству.

В момент, когда вы передаете делегата в MethodThatTakesDelegate, этот контекст теряется. Делегаты хранят только адрес метода, а не контекст информации о методе. Как только это преобразование выполнено, вернуть его невозможно.

Примером того, почему это невозможно, может быть даже отсутствие именованного метода, поддерживающего делегата. Можно использовать ReflectionEmit для генерации метода, который не имеет имени и существует только в памяти. Однако возможно присвоить это объекту Func.

...