简体   繁体   English

如何在C#中捕获表达式树

[英]How to capture an expression tree in C#

I am writing some debug/test code in which I want to both display the original expression and evaluate it, for any arbitrary expression. 我正在编写一些调试/测试代码,我想在其中同时显示原始表达式并对任何任意表达式求值。

For (trivial) example: 对于(平凡的)示例:

IList<string> myString = /* Some string collection expression */

ShowMe(myString.Select(s => s.ToLower()));

Where I implement ShowMe something like: 我在其中实现ShowMe东西:

public void ShowMe(/* Not sure what has to go here */)
{
    /* Not sure what has to go here */
    Console.WriteLine(expression.ToString();
    IEnumerable result = expression.Evaluate(); // or something
    foreach(item in result)
    {
        Console.WriteLine(/* etc. */)
    }
}

And the result will be written to the console as: 并将结果写入控制台:

myString.Select(s => s.ToLower()) myString.Select(s => s.ToLower())

(first item) (第一项)

(next item (下一项

(etc...) (等等...)

In other words, my ShowMe method operates on the expression tree rather than the value of the expression, so that it can both display the expression it was given as well as the computed result. 换句话说,我的ShowMe方法在表达式树上而不是表达式的值上进行操作,因此它既可以显示给定的表达式,也可以显示计算结果。

I can't simply declare ShowMe as: 我不能简单地将ShowMe声明为:

public void ShowMe(Expression expr)

... but if I declare is as ...但是如果我声明是

public void ShowMe(Expression<Func<Enumerable>> expr)

... it sort-of works - I have to call my method with a lambda expression thus: ...它工作原理-我必须使用lambda表达式来调用我的方法,因此:

ShowMe(() => myString.Select(s => s.ToLower()))

... which I don't want to do. ...这是我不想做的。

I'm reasonably sure this can be done... FluentAssertions does it. 我有足够的把握可以做到这一点... FluentAssertions做到了。 For example: if I execute the following line of test code: 例如:如果我执行以下测试代码行:

(1 + 1).Should.Be(3)

I get the following result: 我得到以下结果:

Expected (1 + 1) to be 3, but found 2. 预期(1 +1)为3,但发现为2。

The FluentAssertion has both evaluated the expression (1+1) and captured the expression tree so that was able to display the original expression it evaluated. FluentAssertion既评估了表达式(1 + 1),又捕获了表达式树,从而能够显示其评估的原始表达式。

I can't see how this was done, but I want to do similar. 我看不到这是怎么做的,但我想做类似的事情。 How do I do it? 我该怎么做?

This is per se not possible with any method. 这本身是任何方法都不可能的。

All those libraries just parse the stack trace and extract the file name as well as the line number. 所有这些库仅解析堆栈跟踪并提取文件名以及行号。 Then the expression is extracted from the source code file at the given line (whilst this includes some parsing/validation). 然后在给定的行中从源代码文件中提取表达式(这包括一些解析/验证)。

It is also notably, that the expression can't be shown, if the source code does not exists/is not available. 同样值得注意的是,如果源代码不存在/不可用,则无法显示该表达式。

Figured out an acceptable compromise: 找出可接受的折衷方案:

public static class ObjectHelper
{
    public static void ToConsole<T>(this IEnumerable<T> enumerable, Expression<Func<T,object>> expr)
        where T:class
    {
        var fn = expr.Compile();

        var result = enumerable.Select(s => fn(s));

        Console.WriteLine($"My data selected as {PrettyPrintExpression(expr)}");
        foreach(var element in result)
        {
            Console.WriteLine(/*  etc.  */);
        }
    }

    private static string PrettyPrintExpression(Expression<Func<T,object>> expr)
    {
        // Walk the expression tree to print as desired
    }
}

...which I can invoke as: ...我可以这样调用:

IList<MyObject> list = /* etc. */
list.ToConsole(s => new{/* any members I want out of MyObject */});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM