以人类可读的格式显示表达式
Display an Expression in a human readable format
我正在尝试创建一个扩展方法,如果表达式不匹配,该方法将抛出错误
我有以下代码开始......
public static void Exists<TEntityType>(this IEnumerable<TEntityType> source, Expression<Func<TEntityType, bool>> input) where TEntityType : class
{
if (input is null) throw new ArgumentNullException(nameof(input));
var record = repository.Where(input);
if (record == null)
{
// issue here ...
throw new NotFoundException(typeof(TEntityType).FullName, string.Empty); // todo provide value
}
}
我可以这样调用这段代码...
records.Exists(x => x.Description == methodParameter.PropertyName);
这会根据 属性 正确抛出 NotFoundException。不幸的是,这个错误对用户来说不是很友好,你很难说出关于这个问题的任何细节。我想做的是将表达式简化为更简单的术语。
为了实现这个目标,我尝试了以下方法。
var compileTarget = input.Compile().Target;
里面 compileTarget
是我正在寻找的一些值。在快速观看中它看起来像这样
((System.Runtime.CompilerServices.Closure)compileTarget).Constants[0]
我还可以在即时 Window、局部变量和变量检查器中看到值,但我似乎无法将这些值放入代码中。有什么方法可以解释这些值,以便将整个表达式转换为人类可读的代码吗?
如果 methodParameter.PropertyName
是 test
那么我会寻找类似 Description = test
或 Description is test
?
的东西
这是一个 ExpressionVisitor
的开始,它用它们的值替换了引用常量的 MemberExpression
,假设那些只出现在可评估的情况下(真的,真的未经测试)。
public static class ExpressionExt {
public static Expression Simplify(this Expression e) => (new SimplifyVisitor()).Visit(e);
public static string SimplifiedString(this LambdaExpression e) => e.Body.Simplify().ToString();
}
public class SimplifyVisitor : ExpressionVisitor {
protected override Expression VisitMember(MemberExpression node) {
if (node.Expression is ConstantExpression)
return Expression.Constant(Expression.Lambda<Func<object>>(Expression.Convert(node, typeof(object))).Compile().Invoke(), node.Type);
else
return node;
}
}
有了这些定义,你就可以使用
throw new NotFoundException(typeof(TEntityType).FullName, input.SimplifiedString());
注意:如果您愿意使用DynamicInvoke
,您可以避免访问者中的强制转换:
return Expression.Constant(Expression.Lambda(node).Compile().DynamicInvoke(), node.Type);
我正在尝试创建一个扩展方法,如果表达式不匹配,该方法将抛出错误
我有以下代码开始......
public static void Exists<TEntityType>(this IEnumerable<TEntityType> source, Expression<Func<TEntityType, bool>> input) where TEntityType : class
{
if (input is null) throw new ArgumentNullException(nameof(input));
var record = repository.Where(input);
if (record == null)
{
// issue here ...
throw new NotFoundException(typeof(TEntityType).FullName, string.Empty); // todo provide value
}
}
我可以这样调用这段代码...
records.Exists(x => x.Description == methodParameter.PropertyName);
这会根据 属性 正确抛出 NotFoundException。不幸的是,这个错误对用户来说不是很友好,你很难说出关于这个问题的任何细节。我想做的是将表达式简化为更简单的术语。 为了实现这个目标,我尝试了以下方法。
var compileTarget = input.Compile().Target;
里面 compileTarget
是我正在寻找的一些值。在快速观看中它看起来像这样
((System.Runtime.CompilerServices.Closure)compileTarget).Constants[0]
我还可以在即时 Window、局部变量和变量检查器中看到值,但我似乎无法将这些值放入代码中。有什么方法可以解释这些值,以便将整个表达式转换为人类可读的代码吗?
如果 methodParameter.PropertyName
是 test
那么我会寻找类似 Description = test
或 Description is test
?
这是一个 ExpressionVisitor
的开始,它用它们的值替换了引用常量的 MemberExpression
,假设那些只出现在可评估的情况下(真的,真的未经测试)。
public static class ExpressionExt {
public static Expression Simplify(this Expression e) => (new SimplifyVisitor()).Visit(e);
public static string SimplifiedString(this LambdaExpression e) => e.Body.Simplify().ToString();
}
public class SimplifyVisitor : ExpressionVisitor {
protected override Expression VisitMember(MemberExpression node) {
if (node.Expression is ConstantExpression)
return Expression.Constant(Expression.Lambda<Func<object>>(Expression.Convert(node, typeof(object))).Compile().Invoke(), node.Type);
else
return node;
}
}
有了这些定义,你就可以使用
throw new NotFoundException(typeof(TEntityType).FullName, input.SimplifiedString());
注意:如果您愿意使用DynamicInvoke
,您可以避免访问者中的强制转换:
return Expression.Constant(Expression.Lambda(node).Compile().DynamicInvoke(), node.Type);