自定义ExpressionTree ToString

时间:2013-07-11 11:23:10

标签: c# expression-trees

我正在尝试创建一个ExpressionVisitor,以便将表达式重新创建为输入字符串(有一些例外,捕获变量应显示为文本)。

当我需要访问表达式成员的表达式成员时,我被卡住了。我该如何做到以下几点:

public class Starter
{
    private static void Main(string[] args)
    {
        var test = new SomeClass();
        test.EchoTest();
        Console.ReadLine();
    }
}

public class SomeClass
{
    public string StringMember { get; set; }
    public SomeClass Other { get; set; }

    public void EchoTest()
    {
        var capturedString = "localStringValue";

        Echo((() => "hardcodedString"));//Ok : () => "hardcodedString"
        Echo((() => capturedString));//Ok : () => "localStringValue" (I want the value in this case)
        Echo((() => this.StringMember));//Ok : () => this.StringMember
        Echo((() => this.Other.StringMember));//Failed, expected :() => this.Other.StringMember , received : () => this.Other.this.Other
    }

    private void Echo(Expression<Func<string>> expression)
    {
        Console.WriteLine(PathVisitor.GetPath(expression));
    }
}

public class PathVisitor : ExpressionVisitor
{
    private string _path;

    protected override Expression VisitLambda<T>(Expression<T> node)
    {
        Visit(node.Body);
        _path = string.Format("() => {0}", _path);
        return node;
    }

    protected override Expression VisitConstant(ConstantExpression node)
    {
        _path = string.Format("\"{0}\"", node.Value);
        return node;
    }

    protected override Expression VisitMember(MemberExpression node)
    {
        var generatedClass = null != Attribute.GetCustomAttribute(node.Expression.Type, typeof(CompilerGeneratedAttribute));
        if (node.Expression.NodeType == ExpressionType.Constant && generatedClass)
        {
            var getter = Expression.Lambda(node); //let's eval captured Variable
            _path = string.Format("\"{0}\"", getter.Compile().DynamicInvoke());
        }
        else if (node.Expression.NodeType == ExpressionType.Constant)
        {
            _path = string.Format("this.{0}", node.Member.Name);
        }
        else
        {
            base.Visit(node.Expression);
            var callerPath = _path;
            _path = string.Format("{0}.{1}", callerPath, _path);
        }

        return node;
    }

    public static string GetPath(Expression expression)
    {
        var visitor = new PathVisitor();
        visitor.Visit(expression);
        return visitor._path;
    }
}

2 个答案:

答案 0 :(得分:0)

试试这个......

ExpressionVisitor.VisitMember

答案 1 :(得分:0)

这是预期的行为,因为你将_ this.Other与自身连接起来:


var callerPath = _path;
_path = string.Format("{0}.{1}", callerPath, _path);

你应该把它改成


_path = string.Format("{0}.{1}", _path, node.Member.Name);

即。通过将访问者应用于node.Expression然后添加成员名称来查找前缀。