Получение значений выражений прерывается, когда класс находится в других проектах
Я написал некоторый код, который занимает 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".
и я даже не могу использовать свое приложение.
Я откатил свое извлечение до состояния "он работает локально", чтобы убедиться, что оно действительно сработало, и это сработало. Тем не менее, я заметил, что у меня все еще есть некоторые исключения в моей регистрации, хотя она не бросает на меня, как это происходит, когда это является внешним по отношению к проекту. Я все еще могу использовать свое приложение, несмотря на это.
Повторное перемещение во внешний проект и использование его в качестве ссылки вновь приводит к появлению этих ошибок, и я даже не могу использовать свое приложение.
Новый вопрос: как мне справиться PropertyExpression
s? Они не подвергают 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