递归检查LINQ表达式

时间:2015-12-23 19:26:52

标签: c# linq recursion lambda expression-trees

假设我有这样的表达方式:

e => e.Name.StartsWith(GetArgument())

GetArgument()的定义如下:

public string GetArgument() { return "Lu"; }

我希望将此表达式转换为以下字符串:

"begins_with(Name, Lu)"

我开发了一个表达式访问者,以递归方式访问每个子表达式:

public class MyExpressionTranslator : ExpressionVisitor, IExpressionTranslator<string>
{
     // ....

     //Implementing IExpressionTranslator<string>
     public string Translate(Expression expr)
     {
          //Begin visiting the expression and its sub expressions
          base.Visit(expr);

          // I need to return the string here
          return null;
     }

     // Overrides method from base class ExpressionVisitor
     protected override MethodCallExpression VisitMethodCall(MethodCallExpression expr)
     {
         //This method is called when a method call sub expression is visited

         //For example, I can check if the method being called is "StartsWith"
         if(expr.Method.Name == "StartsWith")
         {
             // I have no idea what to do here
         }

         //Proceeds to visit this expression's sub expressions
         return base.VisitMethodCall(expr);
     }
}

我会按如下方式使用这个类:

MyExpressionTranslator translator = // new MyExpressionTranslator(...)
Expression<Func<SomeClass, bool>> expr = e => e.Name.StartsWith(GetArgument());
string result = translator.Translate(expr);
// result should be "begins_with(Name, Lu)"

为我的基类提供每个表达式类型的virtual访问方法 (无论是常量,参数,方法调用还是其他任何方式)如何构建预期的字符串输出?

1 个答案:

答案 0 :(得分:0)

你想要完成什么?像下面这样的东西可能会起作用。尽管如此,填写其他方法并不容易。

class Program
{
    static void Main(string[] args)
    {
        Expression<Func<TestObject, bool>> expr = e => e.FirstName.StartsWith(GetArgument());
        var visitor = new MyExpressionTranslator();
        var translation = visitor.Translate(expr); // = "begins_with(FirstName, Lu)"
    }

    static string GetArgument()
    {
        return "Lu";
    }
}

class TestObject
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public interface IExpressionTranslator<T>
{
    T Translate(Expression expr);
}

public class MyExpressionTranslator : ExpressionVisitor, IExpressionTranslator<string>
{
    private StringBuilder _sb = null;
    public string Translate(Expression expr)
    {
        _sb = new StringBuilder();
        base.Visit(expr);

        // I need to return the string here
        return _sb.ToString();
    }

    protected override Expression VisitMethodCall(MethodCallExpression expr)
    {
        if (expr.Method.Name == "StartsWith")
        {
            var mainArg = expr.Arguments[0];
            var lambda = Expression.Lambda<Func<string>>(mainArg);
            var arg = lambda.Compile()();

            var member = expr.Object as MemberExpression;
            if (member != null)
            {
                _sb.AppendFormat("begins_with({0}, {1})", member.Member.Name, arg);
            }
            else
            {
                //Don't know what you want here.
                _sb.AppendFormat("begins_with({0}, {1}))", "(obj)", arg);
            }
        }
        return base.VisitMethodCall(expr);
    }
}