2017-09-27 35 views
3

我需要從一個數組中讀取值,並將其作爲表達式提供。如何從表達式提取列表值

我有這樣的方法

public ExpressionAnalizer<TModel> where TModel : class 
{ 
    public string BuildExpression(Expression<Func<TModel, bool>> expression) 
    { 
     if (expression?.Body is MethodCallExpression) 
      return BuildMethodCallExpression(expression);     

     throw new ArgumentException($"The expression '{expression?.Body}' is unsupported"); 
    } 

    public string BuildMethodCallExpression(Expression<Func<TModel, bool>> expression) 
    { 
     var body = expression.Body as MethodCallExpression; 
     //TODO: I can't find a property that has the values of IEnumerable 
     return null; 
    } 
} 

,被稱爲像這樣

//PersonModel is a plain class with some properties. 
var analizer= new ExpressionAnalizer<PersonModel>(""); 
var names = new List<string>() {"n1", "n2", "n3"}; 
//I want to get "Email contains ('n1', 'n2', 'n3')". I can read Email property, the call method name "Contains", but not itself values 
var response = analizer.BuildExpression(x => names.Contains(x.Email)); 

任何想法?我正在考慮編譯表達式,但是我遇到了「Closure」類,因爲System.Runtime.CompilerServices.Closure是私有的,我不能使用它。

順便說一句,我使用.NET 1.0的核心

編輯

我需要得到像

email contains ('n1','n2','n3') 

串和輸入參數必須總是表達式

Expression<Func<TModel, bool>> 

這是因爲在內部使用,這種方法可以接收任何表達,像

x => x.SomeProperty == "n1" 

在內部,我處理expression.Body類型和我有不同的用例的實現。

的情況下,我不明白我怎麼能實現當輸入表達式是

var someList = new List<string>() { "string1", "anotherString", "finalString" }; 
someObject.SomeProperty<SomeTModel>(x => someList.Contains(x.SomeProperty)) 

回答

1

這是全面落實你的ExpressionAnalizer類的,這將給你所需的輸出。

public class ExpressionAnalizer<TModel> where TModel : class 
    { 
     public string BuildExpression(Expression<Func<TModel, bool>> expression) 
     { 
      if (expression?.Body is MethodCallExpression) 
       return BuildMethodCallExpression(expression); 

      throw new ArgumentException($"The expression '{expression?.Body}' is unsupported"); 
     } 

     public string BuildMethodCallExpression(Expression<Func<TModel, bool>> expression) 
     { 
      var body = expression.Body as MethodCallExpression; 

      //Get Method Name 
      string method = body.Method.Name; 

      //Get List of String Values 
      var methodExpression = ResolveMemberExpression(body.Object); 
      var listValues = ReadValue(methodExpression); 
      var vString = string.Format("'{0}'", string.Join("' , '", (listValues as List<string>))); 

      //Read Propery Name 
      var argExpression = ResolveMemberExpression(body.Arguments[0]); 
      var propertyName = argExpression.Member.Name; 

      return $"{propertyName} {method} ({vString})"; 

     } 

     public MemberExpression ResolveMemberExpression(Expression expression) 
     { 

      if (expression is MemberExpression) return (MemberExpression)expression; 
      if (expression is UnaryExpression) return (MemberExpression)((UnaryExpression)expression).Operand; 

      throw new NotSupportedException(expression.ToString()); 
     } 

     private object ReadValue(MemberExpression expression) 
     { 
      if (expression.Expression is ConstantExpression) 
      { 
       return (((ConstantExpression)expression.Expression).Value) 
         .GetType() 
         .GetField(expression.Member.Name) 
         .GetValue(((ConstantExpression)expression.Expression).Value); 
      } 
      if (expression.Expression is MemberExpression) return ReadValue((MemberExpression)expression.Expression); 

      throw new NotSupportedException(expression.ToString()); 
     } 

    } 

用法:

var analizer= new ExpressionAnalizer<PersonModel>(); 
var names = new List<string>() {"n1", "n2", "n3"}; 
var person = new PersonModel{ Email = "Email 1"}; 
var response = analizer.BuildExpression(x => names.Contains(x.Email)); 

響應:

Email Contains ('n1' , 'n2' , 'n3') 
+0

編輯我提供更多信息的問題。基本上,我不能有一個接受IEnumerable參數的方法。你可以幫我嗎 ? –