Here’s a simple C# class that can help debugging Dynamic Language Runtime (v0.9 release) expression trees.  It’s nothing fancy; it just dumps the entire tree to an indented string.  Typically you’d call its static Dump(node) helper from a watch window, or maybe include it in a debug-only region.

Important note:  You can consider this a short-term hack for the v0.9 release of the DLR only.  If you prefer to use the latest DLR source from CodePlex, there’s already a public Dump property available on the Expression class.  Also, if you’re already using Visual Studio 10 / C# 4.0, the Expression Tree Visualizer will probably work just fine :)

using System;
using Microsoft.Linq.Expressions;
using System.Text;

namespace Cjc.Calculation.ExpressionEngine
{
    public class ExpressionTreeDump : BlindExpressionTreeVisitor
    {
        private int indentSize;
        private int indent = 0;
        private StringBuilder sb = new StringBuilder();

        public static string Dump( Expression node )
        {
            var dump = new ExpressionTreeDump();
            dump.Visit( node );
            return dump.Text;
        }

        public ExpressionTreeDump()
            : this( 2 )
        {
        }

        public ExpressionTreeDump( int indentSize )
        {
            this.indentSize = indentSize;
        }

        public string Text
        {
            get { return sb.ToString(); }
        }

        protected override TResult Visit<T, TResult>( T node, Func<T, TResult> p )
        {
            var e = node as Expression;

            var text = ( e != null )
                ? string.Format( "{{{0}}} {1}", e.NodeType, e )
                : node.ToString();

            sb.AppendLine( new string( ' ', indent ) + text );

            indent += indentSize;

            var result = base.Visit<T, TResult>( node, p );

            indent -= indentSize;

            return result;
        }

    }

    public class BlindExpressionTreeVisitor : ExpressionTreeVisitor
    {
        protected virtual TResult Visit<T, TResult>( T node, Func<T, TResult> p )
        {
            return p( node );
        }

        #region Overrides

        protected override Expression VisitAssignment( AssignmentExpression node ) { return Visit( node, e => BaseAssignment( e ) );}
        protected override Expression VisitBinary( BinaryExpression node ) { return Visit( node, e => BaseBinary( e ) ); }
        protected override Expression VisitBlock( Block node ) { return Visit( node, e => BaseBlock( e ) ); }
        protected override CatchBlock VisitCatchBlock( CatchBlock node ) { return Visit( node, e => BaseCatchBlock( e ) ); }
        protected override Expression VisitConditional( ConditionalExpression node ) { return Visit( node, e => BaseConditional( e ) ); }
        protected override Expression VisitConstant( ConstantExpression node ) { return Visit( node, e => BaseConstant( e ) ); }
        protected override Expression VisitDoWhile( DoStatement node ) { return Visit( node, e => BaseDoWhile( e ) ); }
        protected override Expression VisitDynamic( DynamicExpression node ) { return Visit( node, e => BaseDynamic( e ) ); }
        protected override ElementInit VisitElementInit( ElementInit initializer ) { return Visit( initializer, e => BaseElementInit( e ) ); }
        protected override Expression VisitEmpty( EmptyStatement node ) { return Visit( node, e => BaseEmpty( e ) ); }
        protected override Expression VisitExtension( Expression node ) { return Visit( node, e => BaseExtension( e ) ); }
        protected override Expression VisitGoto( GotoExpression node ) { return Visit( node, e => BaseGoto( e ) ); }
        protected override Expression VisitIndex( IndexExpression node ) { return Visit( node, e => BaseIndex( e ) ); }
        protected override Expression VisitInvocation( InvocationExpression node ) { return Visit( node, e => BaseInvocation( e ) ); }
        protected override Expression VisitLabel( LabelExpression node ) { return Visit( node, e => BaseLabel( e ) ); }
        protected override LabelTarget VisitLabelTarget( LabelTarget node ) { return Visit( node, e => BaseLabelTarget( e ) ); }
        protected override Expression VisitLambda( LambdaExpression node ) { return Visit( node, e => BaseLambda( e ) ); }
        protected override Expression VisitListInit( ListInitExpression node ) { return Visit( node, e => BaseListInit( e ) ); }
        protected override Expression VisitLoop( LoopStatement node ) { return Visit( node, e => BaseLoop( e ) ); }
        protected override Expression VisitMemberAccess( MemberExpression node ) { return Visit( node, e => BaseMemberAccess( e ) ); }
        protected override MemberAssignment VisitMemberAssignment( MemberAssignment assignment ) { return Visit( assignment, e => BaseMemberAssignment( e ) ); }
        protected override MemberBinding VisitMemberBinding( MemberBinding binding ) { return Visit( binding, e => BaseMemberBinding( e ) ); }
        protected override Expression VisitMemberInit( MemberInitExpression node ) { return Visit( node, e => BaseMemberInit( e ) ); }
        protected override MemberListBinding VisitMemberListBinding( MemberListBinding binding ) { return Visit( binding, e => BaseMemberListBinding( e ) ); }
        protected override MemberMemberBinding VisitMemberMemberBinding( MemberMemberBinding binding ) { return Visit( binding, e => BaseMemberMemberBinding( e ) ); }
        protected override Expression VisitMethodCall( MethodCallExpression node ) { return Visit( node, e => BaseMethodCall( e ) ); }
        protected override Expression VisitNew( NewExpression node ) { return Visit( node, e => BaseNew( e ) ); }
        protected override Expression VisitNewArray( NewArrayExpression node ) { return Visit( node, e => BaseNewArray( e ) ); }
        protected override Expression VisitParameter( ParameterExpression node ) { return Visit( node, e => BaseParameter( e ) ); }
        protected override Expression VisitReturn( ReturnStatement node ) { return Visit( node, e => BaseReturn( e ) ); }
        protected override Expression VisitRuntimeVariables( LocalScopeExpression node ) { return Visit( node, e => BaseRuntimeVariables( e ) ); }
        protected override Expression VisitScope( ScopeExpression node ) { return Visit( node, e => BaseScope( e ) ); }
        protected override Expression VisitSwitch( SwitchStatement node ) { return Visit( node, e => BaseSwitch( e ) ); }
        protected override SwitchCase VisitSwitchCase( SwitchCase node ) { return Visit( node, e => BaseSwitchCase( e ) ); }
        protected override Expression VisitThrow( ThrowStatement node ) { return Visit( node, e => BaseThrow( e ) ); }
        protected override Expression VisitTry( TryStatement node ) { return Visit( node, e => BaseTry( e ) ); }
        protected override Expression VisitTypeBinary( TypeBinaryExpression node ) { return Visit( node, e => BaseTypeBinary( e ) ); }
        protected override Expression VisitUnary( UnaryExpression node ) { return Visit( node, e => BaseUnary( e ) ); }

        #endregion

        #region Base invokers

        private Expression BaseAssignment( AssignmentExpression node ) { return base.VisitAssignment( node ); }
        protected Expression BaseBinary( BinaryExpression node ) { return base.VisitBinary( node ); }
        protected Expression BaseBlock( Block node ) { return base.VisitBlock( node ); }
        protected CatchBlock BaseCatchBlock( CatchBlock node ) { return base.VisitCatchBlock( node ); }
        protected Expression BaseConditional( ConditionalExpression node ) { return base.VisitConditional( node ); }
        protected Expression BaseConstant( ConstantExpression node ) { return base.VisitConstant( node ); }
        protected Expression BaseDoWhile( DoStatement node ) { return base.VisitDoWhile( node ); }
        protected Expression BaseDynamic( DynamicExpression node ) { return base.VisitDynamic( node ); }
        protected ElementInit BaseElementInit( ElementInit initializer ) { return base.VisitElementInit( initializer ); }
        protected Expression BaseEmpty( EmptyStatement node ) { return base.VisitEmpty( node ); }
        protected Expression BaseExtension( Expression node ) { return base.VisitExtension( node ); }
        protected Expression BaseGoto( GotoExpression node ) { return base.VisitGoto( node ); }
        protected Expression BaseIndex( IndexExpression node ) { return base.VisitIndex( node ); }
        protected Expression BaseInvocation( InvocationExpression node ) { return base.VisitInvocation( node ); }
        protected Expression BaseLabel( LabelExpression node ) { return base.VisitLabel( node ); }
        protected LabelTarget BaseLabelTarget( LabelTarget node ) { return base.VisitLabelTarget( node ); }
        protected Expression BaseLambda( LambdaExpression node ) { return base.VisitLambda( node ); }
        protected Expression BaseListInit( ListInitExpression node ) { return base.VisitListInit( node ); }
        protected Expression BaseLoop( LoopStatement node ) { return base.VisitLoop( node ); }
        protected Expression BaseMemberAccess( MemberExpression node ) { return base.VisitMemberAccess( node ); }
        protected MemberAssignment BaseMemberAssignment( MemberAssignment assignment ) { return base.VisitMemberAssignment( assignment ); }
        protected MemberBinding BaseMemberBinding( MemberBinding binding ) { return base.VisitMemberBinding( binding ); }
        protected Expression BaseMemberInit( MemberInitExpression node ) { return base.VisitMemberInit( node ); }
        protected MemberListBinding BaseMemberListBinding( MemberListBinding binding ) { return base.VisitMemberListBinding( binding ); }
        protected MemberMemberBinding BaseMemberMemberBinding( MemberMemberBinding binding ) { return base.VisitMemberMemberBinding( binding ); }
        protected Expression BaseMethodCall( MethodCallExpression node ) { return base.VisitMethodCall( node ); }
        protected Expression BaseNew( NewExpression node ) { return base.VisitNew( node ); }
        protected Expression BaseNewArray( NewArrayExpression node ) { return base.VisitNewArray( node ); }
        protected Expression BaseParameter( ParameterExpression node ) { return base.VisitParameter( node ); }
        protected Expression BaseReturn( ReturnStatement node ) { return base.VisitReturn( node ); }
        protected Expression BaseRuntimeVariables( LocalScopeExpression node ) { return base.VisitRuntimeVariables( node ); }
        protected Expression BaseScope( ScopeExpression node ) { return base.VisitScope( node ); }
        protected Expression BaseSwitch( SwitchStatement node ) { return base.VisitSwitch( node ); }
        protected SwitchCase BaseSwitchCase( SwitchCase node ) { return base.VisitSwitchCase( node ); }
        protected Expression BaseThrow( ThrowStatement node ) { return base.VisitThrow( node ); }
        protected Expression BaseTry( TryStatement node ) { return base.VisitTry( node ); }
        protected Expression BaseTypeBinary( TypeBinaryExpression node ) { return base.VisitTypeBinary( node ); }
        protected Expression BaseUnary( UnaryExpression node ) { return base.VisitUnary( node ); }

        #endregion
    }
}

About these ads