Skip to content
Zev Spitz edited this page Jun 4, 2019 · 19 revisions

String rendering library

Given an expression tree:

Expression<Func<Person, bool>> expr = p =>
    p.DOB.DayOfWeek == DayOfWeek.Tuesday;

.NET provides a mechanism for representing an expression tree as a string, using the built-in .ToString:

Console.WriteLine(expr);
/*
    p => (Convert(p.DOB.DayOfWeek) == 2)
*/

However, the generated string has a number of usability issues:

  • conversions (Convert(...) vs (int)...),
  • type names use the Type.Name property (List`1 vs List<string>),
  • closed-over variables are rendered as members of a hidden class: (value(sampleCode.Program+<>c__DisplayClass0_0).i vs i).

There is also the DebugView property, available only while debugging, which uses a special syntax to represent more of the expression tree's information:

.Lambda #Lambda1<System.Func`2[sampleCode.Person,System.Boolean]>(sampleCode.Person $p) {
  (System.Int32)($p.DOB).DayOfWeek == 2
}

but the additional information is not always necessary, and can make it even harder to read.

The string rendering library is implemented as a set of .ToString set of extension methods on the various types used in expression trees. You pass in the name of the formatter to use when rendering the expression tree:

Console.WriteLine(expr.ToString("C#"));
/*
    (Person p) => (int)p.DOB.DayOfWeek == 2
*/

Console.WriteLine(expr.ToString("Visual Basic"));
/*
    Function(p As Person) CInt(p.DOB.DayOfWeek) = 2
*/

Visualizer

The visualizer shows the various objects that make up the expression tree, in a treeview control:

Expression tree with a loop, a label, and a condition

The emphasis is on displaying the structure of the expression tree:

  • Not every property becomes a child node; only specific types which are part of the expression tree's structure, such as Expression and CaseBlock
  • Properties which return collections -- LambdaExpression.Parameters, Block.RuntimeVariables -- are not rrendered as child nodes. Instead, the individual elements of the collections are rendered as child nodes -- Lambda -> Parameters[0] instead of Lambda -> Parameters -> [0]

Clone this wiki locally