当 class 在其他项目中时获取表达式值中断
Getting expression values breaks when class is in other projects
我已经编写了一些代码,这些代码采用 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
和 returns 中存在的参数值 IEnumerable
。这是我在最初使用的项目中编写此代码时得到的行为,我可以看到正确输出的结果参数值。我什至将其移至测试床项目以测试代码,并且在那里也运行良好。但是,当我将 .cs 文件放在另一个项目中,更新命名空间并引用它以便能够广泛使用它时,我会遇到异常,例如
System.InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.PropertyExpression' to type 'System.Linq.Expressions.ConstantExpression'.
我什至无法使用我的应用程序。
我已将提取恢复到 "it works locally" 状态,以确保它确实有效,而且确实有效。但是,我注意到我的日志记录中仍然有一些异常,即使它没有像在项目外部时那样抛出我。尽管如此,我仍然可以使用我的应用程序。
重复移动到外部项目并通过引用使用它会重新引入这些错误,我什至无法使用我的应用程序。
新问题:如何处理 PropertyExpression
s?他们不公开 Value
属性 并且是内部的,所以我没有转换和检查。 MemberExpression
也没有 Value
属性.
最简单的解决方案是根本不依赖表达式的形状,让表达式树库通过构建 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
我已经编写了一些代码,这些代码采用 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
和 returns 中存在的参数值 IEnumerable
。这是我在最初使用的项目中编写此代码时得到的行为,我可以看到正确输出的结果参数值。我什至将其移至测试床项目以测试代码,并且在那里也运行良好。但是,当我将 .cs 文件放在另一个项目中,更新命名空间并引用它以便能够广泛使用它时,我会遇到异常,例如
System.InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.PropertyExpression' to type 'System.Linq.Expressions.ConstantExpression'.
我什至无法使用我的应用程序。
我已将提取恢复到 "it works locally" 状态,以确保它确实有效,而且确实有效。但是,我注意到我的日志记录中仍然有一些异常,即使它没有像在项目外部时那样抛出我。尽管如此,我仍然可以使用我的应用程序。
重复移动到外部项目并通过引用使用它会重新引入这些错误,我什至无法使用我的应用程序。
新问题:如何处理 PropertyExpression
s?他们不公开 Value
属性 并且是内部的,所以我没有转换和检查。 MemberExpression
也没有 Value
属性.
最简单的解决方案是根本不依赖表达式的形状,让表达式树库通过构建 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