Получение значений выражений прерывается, когда класс находится в других проектах

Я написал некоторый код, который занимает Expression и действует как прокси для совершения определенных звонков. Основной кусок кода, который делает эту работу, такой

private static IEnumerable<object> GetArguments(MethodCallExpression body)
{
    IEnumerable<object> arguments =
        body.Arguments.Select(
            expression =>
            {
                MemberExpression member = expression as MemberExpression;
                return ((dynamic) member.Member).GetValue(((ConstantExpression) member.Expression).Value);
            });

    return arguments;
}

Это получает значения параметров, присутствующих в Expression и возвращает их в IEnumerable, Это поведение, которое я получаю, когда пишу это в первоначально потребляющем проекте, и я вижу, что результирующие значения аргументов выводятся правильно. Я даже перенес это в проект тестового стенда, чтобы протестировать код, и он также работал там хорошо. Однако, когда я помещаю файлы.cs в другой проект, обновляю пространства имен и ссылаюсь на него, чтобы иметь возможность широко использовать его, я получаю исключения, такие как

System.InvalidCastException: Невозможно привести объект типа "System.Linq.Expressions.PropertyExpression" к типу "System.Linq.Expressions.ConstantExpression".

и я даже не могу использовать свое приложение.

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

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

Новый вопрос: как мне справиться PropertyExpressions? Они не подвергают Value собственности и являются внутренними, так что я не брошен и не проверен. MemberExpression также не имеет Value имущество.

2 ответа

Решение

Простейшим решением было бы вообще не полагаться на форму выражений и позволить библиотеке дерева выражений оценить каждое подвыражение для вас, создав LambdaExpression а затем с помощью Compile() на нем и выполнение возвращенного делегата:

private static IEnumerable<object> GetArguments(MethodCallExpression body)
{
    return body.Arguments.Select(
        expression => Expression.Lambda<Func<object>>(
            Expression.Convert(expression, typeof(object))).Compile()());
}

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

Вы должны оценить выражение и не полагаться на его форму. Самый простой способ - позвонить .Compile().Invoke(), но это медленно и создает утечку памяти. Вы можете избежать этого, интерпретируя выражение (рекурсивно обходя его с посетителем и выполняя операции над ним вручную) или кэшируя результаты компиляции. Я написал библиотеку, которая может выполнять обе задачи, быстро и в течение некоторого времени уже используется в производстве: https://github.com/Miaplaza/expression-utils

Другие вопросы по тегам