InvalidOperationException (лямбда-параметр не находится в области видимости) при попытке скомпилировать лямбда-выражение - PullRequest
1 голос
/ 01 мая 2010

Я пишу парсер выражений, чтобы сделать мой API более удобным для рефакторинга и менее подверженным ошибкам. по сути, я хочу, чтобы пользователь написал такой код:

repository.Get(entity => entity.Id == 10);

вместо:

repository.Get<Entity>("Id", 10);

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

Поработав некоторое время, я перестал пытаться охватить все возможные случаи самостоятельно. и решил использовать каркас, чтобы выполнить всю тяжелую работу за меня, скомпилировав и выполнив правую часть выражения. соответствующая часть кода выглядит так:

public static KeyValuePair<string, object> Parse<T>(Expression<Func<T, bool>> expression)
{
    var binaryExpression = (BinaryExpression)expression.Body;

    string memberName = ParseMemberName(binaryExpression.Left);
    object value = ParseValue(binaryExpression.Right);

    return new KeyValuePair<string, object>(memberName, value);
}

private static object ParseValue(Expression expression)
{
    Expression conversionExpression = Expression.Convert(expression, typeof(object));
    var lambdaExpression = Expression.Lambda<Func<object>>(conversionExpression);
    Func<object> accessor = lambdaExpression.Compile();
    return accessor();
}

Теперь я получаю исключение InvalidOperationException (параметр Lambda не входит в область действия) в строке компиляции. Когда я гуглил решение, я столкнулся с похожими вопросами, которые включали создание выражения вручную и не предоставляли все части, или пытались опираться на параметры, имеющие одно и то же имя, а не одну и ту же ссылку. Я не думаю, что это так, потому что я снова использую данное выражение.

EDIT

Это один из нерабочих сценариев:

ExpressionParser.Parse (entity => entity.InternalClass.Id == entity.Id);

Буду признателен, если кто-нибудь подскажет мне об этом. Спасибо.

1 Ответ

1 голос
/ 01 мая 2010

Версия с константой отлично работает с кодом, как опубликовано. Можете ли вы проиллюстрировать пример выражения, где оно не работает?

Когда вы видите это, это означает, что ваш Right пытается использовать параметр; в Expression<Func<T, bool>> есть только один параметр (первый, типа T). Например, я ожидал бы, что следующее сломается (и это делает):

        // find people who are their own boss
        var pair = Parse<Foo>(entity => entity.Id == entity.ManagerId);

Ре сложности; существует много случаев, которые можно проанализировать без компиляции; Я использую стратегию «попробуй и отступи к компиляции». См. Методы Evaluate и TryEvaluate, здесь .

...