【问题标题】:Wrapping an Expression Tree with a Logger用 Logger 包装表达式树
【发布时间】:2015-12-01 00:30:59
【问题描述】:

我正在表达式树中做一些工作。当您在表达式树上调用 ToString() 时,您会得到一些可爱的诊断文本(这里是一个示例):

 ((Param_0.Customer.LastName == "Doe") 
     AndAlso ((Param_0.Customer.FirstName == "John") 
     Or (Param_0.Customer.FirstName == "Jane")))

所以我写了这段代码,试图用一些日志记录功能包装表达式:

public Expression WithLog(Expression exp)
{
    return Expression.Block(exp, Expression.Call(
        typeof (Debug).GetMethod("Print",
            new Type [] { typeof(string) }),
        new [] { exp } ));
}

我对推断 ToString() 用法的方法调用有一半的预期,但我认为这是一个编译时特性。当我执行此操作时,我收到错误:

“System.Boolean”类型的表达式不能用于“Void Print(System.String)”方法的“System.String”类型的参数

很公平。但是当我把它改成这样时:

public Expression WithLog(Expression exp)
{
    return Expression.Block(exp, Expression.Call(
        typeof (Debug).GetMethod("Print",
            new Type [] { typeof(string) }),
        new [] { exp.ToString() } ));
}

它无法编译。为什么?我需要做什么来解决这个问题?

【问题讨论】:

  • 它无法编译,因为它需要一个Expressions 的数组,但你给它的是一个字符串数组。您需要将其更改为在 Expression.Constant(exp) 上调用 ToString 的表达式

标签: c# expression-trees


【解决方案1】:

根据我的评论,它期待Expression[],但你已经通过了string[]。你可以这样做,它会立即在exp 上运行ToString()

public Expression WithLog(Expression exp)
{
    return Expression.Block(Expression.Call(
        typeof (Debug).GetMethod("Print",
            new Type [] { typeof(string) }),
        new [] { Expression.Constant(exp.ToString()) } ), exp);
}

产生:

Print("c => ((c.LastName == "Doe") AndAlso ((c.FirstName == "John") OrElse (c.LastName == "Jane")))")

或者,您可以将Expression.Constant(exp.ToString()) 更改为对expToString 调用,以便在您调用表达式时执行ToString

public Expression WithLog(Expression exp)
{
    return Expression.Block(Expression.Call(
        typeof (Debug).GetMethod("Print",
            new Type [] { typeof(string) }),
        new [] { Expression.Call(Expression.Constant(exp), exp.GetType().GetMethod("ToString")) } ), exp);
}

这给出了:

Print(c => ((c.LastName == "Doe") AndAlso ((c.FirstName == "John") OrElse (c.LastName == "Jane"))).ToString())

【讨论】:

  • 显然我对它如何工作的一些假设是无效的,因为我现在收到错误The binary operator Or is not defined for the types 'System.Void' and 'System.Void' ...但无论如何我都会将它标记为已完成,因为它解决了问题在眼前。谢谢。
  • @RobertHarvey 很高兴能帮上忙。至于您的其他错误,我可以假设您正在做类似 Expression.OrElse(WithLog(...), ...) 的事情吗?如果 的情况,您需要更改 WithLog 方法中的块以返回原始表达式。就目前而言,它正在编译为(e) => Print(exp) || e.LastName = "Doe"
  • 更像WithLog(Expression.OrElse(blah))。但是,是的,类似的东西。你是对的;我想我需要返回原始表达式,而不是新表达式。我对表达式树很陌生。
  • 啊,是因为Expression.Block的参数弄错了。它目前对exp 什么都不做,执行Print,并从Print 返回空结果。如果将其从 Expression.Block(exp, --printExpression--) 更改为 Expression.Block(--printExpression--, exp),它应该可以正常工作
猜你喜欢
  • 2015-11-25
  • 2015-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-05
相关资源
最近更新 更多