GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — GitHub - zspitz/ExpressionTreeToString: String representations of expression trees + library of expression tree objects

BranchesTags
Open more actions menu

Latest commit

 

History

541 Commits
541 Commits

Folders and files

NameName
Last commit message
Last commit date
.github/ISSUE_TEMPLATE
.github/ISSUE_TEMPLATE
 
 
Library
Library
 
 
TestObjects.VB
TestObjects.VB
 
 
TestObjects
TestObjects
 
 
Tests.DataGenerator
Tests.DataGenerator
 
 
Tests
Tests
 
 
_expressionTestObjectsTest
_expressionTestObjectsTest
 
 
_tests
_tests
 
 
.editorconfig
.editorconfig
 
 
.gitattributes
.gitattributes
 
 
.gitignore
.gitignore
 
 
CONTRIBUTING.md
CONTRIBUTING.md
 
 
ExpressionTreeToString.sln
ExpressionTreeToString.sln
 
 
LICENSE
LICENSE
 
 
README.md
README.md
 
 
appveyor.yml
appveyor.yml
 
 

Repository files navigation

Expression Tree To String

AppVeyor build status Tests NuGet Status       Test objects: NuGet TestObjects Status

Targets .NET Standard 2.0 and above / Framework 4.5.2 and above

Provides a ToString extension method which returns a string representation of an expression tree (an object inheriting from System.Linq.Expressions.Expression).

Expression<Func<bool>> expr = () => true;

Console.WriteLine(expr.ToString("C#"));
// prints: () => true

Console.WriteLine(expr.ToString("Visual Basic"));
// prints: Function() True

Console.WriteLine(expr.ToString("Factory methods", "C#"));
// prints:
/*
    // using static System.Linq.Expressions.Expression

    Lambda(
        Constant(true)
    )
*/

Console.WriteLine(expr.ToString("Object notation", "C#"));
// prints:
/*
    new Expression<Func<bool>> {
        NodeType = ExpressionType.Lambda,
        Type = typeof(Func<bool>),
        Body = new ConstantExpression {
            Type = typeof(bool),
            Value = true
        },
        ReturnType = typeof(bool)
    }
*/

Console.WriteLine(expr.ToString("Object notation", "Visual Basic"));
// prints:
/*
    New Expression(Of Func(Of Boolean)) With {
        .NodeType = ExpressionType.Lambda,
        .Type = GetType(Func(Of Boolean)),
        .Body = New ConstantExpression With {
            .Type = GetType(Boolean),
            .Value = True
        },
        .ReturnType = GetType(Boolean)
    }
*/

Console.WriteLine(expr.ToString("Textual tree"));
// prints:
/*
    Lambda (Func<bool>)
        Body - Constant (bool) = True
*/

var b = true;
Expression<Func<int>> expr1 = () => b ? 1 : 0;
Console.WriteLine(expr1.ToString("ToString"));
// prints:
/*
    () => IIF(value(_tests.Program+<>c__DisplayClass0_0).b, 1, 0)
*/

Console.WriteLine(expr1.ToString("DebugView"));
// prints:
/*
    .Lambda #Lambda1<System.Func`1[System.Int32]>() {
        .If (
            .Constant<_tests.Program+<>c__DisplayClass0_0>(_tests.Program+<>c__DisplayClass0_0).b
        ) {
            1
        } .Else {
            0
        }
    }
*/

Expression<Func<Person, bool>> filter = p => p => p.LastName == "A" || p.FirstName == "B" || p.DOB == DateTime.MinValue || p.LastName == "C" || p.FirstName == "D";
Console.WriteLine(filter.ToString("Dynamic LINQ", "C#"));
// prints:
/*
    "LastName in (\"A\", \"C\") || FirstName in (\"B\", \"D\") || DOB == DateTime.MinValue"
*/

Features:

  • Multiple writers:

    • Pseudo-code in C# or VB.NET
    • Factory method calls which generate this expression
    • Object notation, using object initializer and collection initializer syntax to describe objects
    • Textual tree, focusing on the properties related to the structure of the tree
    • ToString and DebugView reimplementation
    • Dynamic LINQ equivalent to the expression
  • For C# and VB pseudo-code representations:

    • Extension methods are rendered as instance methods

      Expression<Func<int, int>> expr = x => Enumerable.Range(1, x).Select(y => x * y).Count();
      Console.WriteLine(expr.ToString("C#"));
      // prints: (int x) => Enumerable.Range(1, x).Select((int y) => x * y).Count()
    • Closed-over variables are rendered as simple identifiers (instead of member access on the hidden compiler-generated class)

      var i = 7;
      var j = 8;
      Expression<Func<int>> expr = () => i + j;
      Console.WriteLine(expr.ToString("C#"));
      // prints: () => i + j
    • Calls to String.Concat and String.Format are mapped to the + operator and string interpolation, respectively (where possible):

      var name = "World";
      Expression<Func<string>> expr = () => string.Format("Hello, {0}!", name);
      Console.WriteLine(expr.ToString("C#"));
      // prints: () => $"Hello, {name}!"
    • Unnecessary conversions are not rendered:

      Expression<Func<IEnumerable<char>>> expr = () => (IEnumerable<char>)"abcd";
      Console.WriteLine(expr.ToString("C#"));
      // prints: () => "abcd"
    • Comparisons against an enum or char are rendered properly, not as comparison to int-converted value:

      var dow = DayOfWeek.Sunday;
      Expression<Func<bool>> expr = () => DateTime.Today.DayOfWeek == dow;
      
      Console.WriteLine(expr.ToString("Textual tree", "C#"));
      // prints:
      /*
        Lambda (Func<bool>)
            · Body - Equal (bool) = false
                · Left - Convert (int) = 3
                    · Operand - MemberAccess (DayOfWeek) DayOfWeek = DayOfWeek.Wednesday
                        · Expression - MemberAccess (DateTime) DateTime.Today = 30/09/2020 12:00:00 am
                · Right - Convert (int) = 0
                    · Operand - MemberAccess (DayOfWeek) dow = DayOfWeek.Sunday
                        · Expression - Constant (<closure>) = #<closure>      
      */
      
      Console.WriteLine(expr.ToString("C#"));
      // prints: () => DateTime.Today.DayOfWeek == dow
  • Each representation (including the ToString and DebugView renderers) can return the start and length of the substring corresponding to any of the paths of the tree's nodes, which can be used to find the substring corresponding to a given node in the tree:

    var s = expr.ToString("C#", out var pathSpans);
    Console.WriteLine(s);
    // prints: (Person p) => p.DOB.DayOfWeek == DayOfWeek.Tuesday
    
    (int start, int length) = pathSpans["Body.Left.Operand"];
    Console.WriteLine(s.Substring(start, length));
    // prints: p.DOB.DayOfWeek
  • Type names are rendered using language syntax and keywords, instead of the Type.Name property; e.g. List<string> or List(Of Date) instead of List`1

  • Supports the full range of types in System.Linq.Expressions, including .NET 4 expression types, and DynamicExpression

    • Expression (and derived types)
    • ElementInit
    • MemberBinding (and derived types)
    • SwitchCase
    • CatchBlock
    • LabelTarget
  • Extensibility -- allows creating custom renderers, or inheriting from existing renderers, to handle your own Expression-derived types

For more information, see the wiki.

Feedback

  • Star the project
  • File an issue

About

String representations of expression trees + library of expression tree objects

Topics

code-generationcsharpexpression-treetest-datatostringvb-netvisual-basic-net

Resources

Readme
MIT license

Contributing

Contributing
Activity

Stars

165 stars

Watchers

3 watching

Forks

13 forks
Report repository

Releases

Packages

Used by

Contributors

Languages

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.