2015-12-23 55 views
1

比方說,我有這樣的表達:遞歸檢查LINQ表達式

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

GetArgument()定義如下:

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

我想這個表達式被翻譯成以下字符串:

"begins_with(Name, Lu)" 

我開發了一個表達式訪問器來訪問rec中的每個子表達式ursive方式:

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訪問方法(可能是一個常數,一個參數,一個方法調用,或任何其他)我該如何構建預期的字符串輸出?

+0

您正在爲特定情況提供預期輸出。其他情況下,例如屬性訪問或循環可能如何? –

+0

@YacoubMassad其實,我打算將這個特定的案例解決方案擴展到任何其他用例。這裏的核心問題是我不知道如何遞歸地創建字符串。一旦解決了,我可以設法做其他事情。 –

+1

提示:使用私有字段StringBuilder。 –

回答

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); 
    } 
}