如何在C#

时间:2018-08-10 18:12:03

标签: c# expression-trees

我正在编写一些调试/测试代码,我想在其中同时显示原始表达式并对任意表达式进行评估。

(简单的)示例:

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

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

我在其中实现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. */)
    }
}

结果将被写入控制台:

  

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

     

(第一项)

     

(下一个项目

     

(等...)

换句话说,我的ShowMe方法在表达式树上而不是表达式的值上操作,因此它既可以显示给定的表达式,又可以显示计算结果。

我不能简单地将ShowMe声明为:

public void ShowMe(Expression expr)

...但是如果我声明为

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

...它 sort-of 的工作原理-我必须这样用lambda表达式调用我的方法:

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

...我不想做。

我有足够的把握可以做到这一点... FluentAssertions做到了。例如:如果我执行以下测试代码行:

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

我得到以下结果:

  

预计(1 +1)为3,但发现为2。

FluentAssertion既评估了表达式(1 + 1),又捕获了表达式树,从而能够显示其评估的原始表达式。

我看不到这是怎么做的,但我想做类似的事情。我该怎么办?

2 个答案:

答案 0 :(得分:2)

使用任何方法本身都是不可能的。

所有这些库仅解析堆栈跟踪并提取文件名以及行号。然后在给定的行中从源代码文件中提取表达式(这包括一些解析/验证)。

还值得注意的是,如果源代码不存在/不可用,则无法显示该表达式。

答案 1 :(得分:0)

找出了可以接受的折衷方案:

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
    }
}

...我可以这样调用:

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