2012-10-01 46 views
1

我有一個名爲類HomeInfo字符串條件<T>

public class HomeInfo 
{ 
    public int ID {get;set;} 
    public string OwnerName {get;set;} 
    public string Address {get;set;} 
    public int EstimatedValue {get;set;} 
} 

我從服務器獲取數據,我添加到List<HomeInfo> listHomeInfo

現在在我的GUI我需要讓基於用戶輸入濾波結果,所以我的客戶想要一個估算值的文本框,並且他想要在那裏輸入文本,如'> 30k和< 50k'或'> 50k',我解析並轉換這些值並創建類的對象

public class ExpressionValue 
{ 
    public float? FirstDigit { get; set; } 
    /// <summary> 
    /// >, >=, <,<= 
    /// </summary> 
    public string FirstExpCondition { get; set; } 
    /// <summary> 
    /// OR, AND 
    /// </summary> 
    public string ConditionOperator { get; set; } 
    public float SecondDigit { get; set; } 
    public string SecondExpCondition { get; set; } 
} 

使用ExpressionValue對象我能夠創建適當的條件字符串。 現在我能夠創造條件串像「EstimatedValue> 30000 EstimatedValue < 60000」或「EstimatedValue < 50000」

我不知道我怎樣纔能有效地對「名單listHomeInfo」適用這個條件,因爲遠我知道List<T>.Where()不支持字符串條件。我知道一個解決方法是將列表轉換爲DataTable並使用Select(string expression)方法,然後將DataRow[]轉換爲List<HomeInfo>,但我認爲可能有更好的方法來實現這一點。

[編輯]

我創建了兩個方法來幫助我,但我得到的例外「的二元運算GREATERTHAN沒有爲類型‘System.Single’和‘System.Double’定義」。創建BinaryExpression時。

public static Expression<Func<T, bool>> ParseExpressionCondition<T>(string expression, string fieldName) 
    { 
     try 
     { 
      string decimalNumRegex = @"\d+(\.\d{1,2})?"; 
      List<string> matchPatterns = new List<string>() { ">=", ">", "<=", "<" }; 
      ExpressionValue expValue = new ExpressionValue(); 
      Dictionary<string, string> conditions = new Dictionary<string, string>(); 
      var parameter = Expression.Parameter(typeof(T), typeof(T).ToString()); 
      //var lhs = Expression.GreaterThan(Expression.Property(parameter, "EstimatedValue"), Expression.Constant(30000)); 
      BinaryExpression lhs = null, rhs = null; 
      object objectValue = null; 
      string condOperator = null; 
      foreach (string pattern in matchPatterns) 
      { 
       Match match = Regex.Match(expression, pattern + decimalNumRegex); 

       if (match.Success) 
       { 
        //get digit part 
        double digit = double.Parse(Regex.Match(match.Value, decimalNumRegex).Value); 
        if (!expValue.FirstDigit.HasValue) 
        { 
         objectValue = digit; 
         condOperator = match.Value.Replace(digit.ToString(), ""); 
         lhs = GetBinaryExpression(parameter, fieldName, objectValue, condOperator); 
        } 
        else 
        { 
         objectValue = digit; 
         condOperator = match.Value.Replace(digit.ToString(), ""); 
         rhs = GetBinaryExpression(parameter, fieldName, objectValue, condOperator); 
        } 
       } 
      } 

      if (expression.ToLower().Contains("and")) 
       return Expression.Lambda<Func<T, bool>>(Expression.And(lhs, rhs), parameter); 
      else if (expression.ToLower().Contains("or")) 
       return Expression.Lambda<Func<T, bool>>(Expression.Or(lhs, rhs), parameter); 


      return null; 
     } 
     catch (Exception ex) 
     { 
      Logger.WriteLog(ex); 
      throw ex; 
     } 
    } 

    private static BinaryExpression GetBinaryExpression(ParameterExpression paraExp, string fieldName, object expressionValue, string conditionOperator) 
    { 
     try 
     { 
      BinaryExpression binExp = null; 
      MemberExpression expressionLeft = Expression.Property(paraExp, fieldName); 
      Expression expressionRight = Expression.Constant(expressionValue); 
      switch (conditionOperator) 
      { 
       case ">": 
        binExp = Expression.GreaterThan(expressionLeft, expressionRight); 
        break; 
       case ">=": 
        binExp = Expression.GreaterThanOrEqual(expressionLeft, expressionRight); 
        break; 
       case "<": 
        binExp = Expression.LessThan(expressionLeft, expressionRight); 
        break; 
       case "<=": 
        binExp = Expression.LessThanOrEqual(expressionLeft, expressionRight); 
        break; 
      } 
      return binExp; 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
    } 
+1

你爲什麼想要保存條件爲一個字符串?它是由用戶輸入的嗎?爲什麼不使用表達式樹? –

+1

'List.Where()不支持字符串條件' - 確實如此,如果字符串是你正在評估的條件。 –

+0

這個例子看起來並不需要如此高度的自定義將查詢放在一起,但總是有[動態LINQ庫](http://weblogs.asp.net/scottgu/archive/2008/01 /07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx)。 – herzmeister

回答

2

假設你已經在某種程度上已經實現瞭解析邏輯,我會建議生成一個表達式樹(而不是使用你自己定製的ExpressionValue類)。

E.g. 'EstimatedValue> 30000 AND EstimatedValue < 60000' 可以成爲以下形式的表達式樹:

var parameter = Expression.Parameter(typeof(HomeInfo), "homeInfo"); 
var lhs = Expression.GreaterThan(Expression.Property(parameter, "EstimatedValue"), Expression.Constant(30000)); 
var rhs = Expression.LessThan(Expression.Property(parameter, "EstimatedValue"), Expression.Constant(60000)); 
var expression = Expression.Lambda<Func<HomeInfo, bool>>(Expression.AndAlso(lhs, rhs), parameter); 

列表可以然後使用所生成的表達式樹來查詢如下:

var results = listHomeInfo.AsQueryable().Where(expression); 
+0

+1,因爲我從來沒有聽過表情樹,我現在愛你;-)! –

+0

@Iridium我創建了兩種方法來幫助我,但我得到了異常「二元運算符GreaterThan沒有爲'System.Single'和'System.Double'類型定義。」創建BinaryExpression時。 –

+0

@DineshAhuja問題在於Expression.GreaterThan()的一側是雙精度型,另一側是浮點型(單精度)。 float不會被自動上傳爲double來允許比較(因爲如果你直接比較float和double),所以你需要手動進行比較。我建議你首先嚐試用「float digit = float.Parse(Regex.Match())替換」double digit = double.Parse(Regex.Match(match.Value ...) match.Value ...「(即將值解析爲float而不是double) – Iridium

-1

使用LinqToObjects

List<HomeInfo> homeInfos = new List<HomeInfo>(); 

homeInfos.Where(x => x.EstimatedValue > 1000).Where(x => x.EstimatedValue < 10000); 
+0

過濾需要基於用戶輸入,而不是硬編碼的編譯時間值。 – Servy

+0

您需要將表達式的結果賦值給一個變量; 'Where'不會修改原始列表,並且結果將隨着此代碼而丟失。 – phoog

+0

我不知道如何在'List listHomeInfo'上有效應用此條件,因爲據我所知,列表 .Where()不支持字符串條件在一天結束時,他想將條件應用於列表而不是使用表達式條件,使用LINQ他可以很容易地將其排除。 – Larry

0

不要重新發明輪子:NCalc做這樣的東西了。

隨着一個名爲EstimatedValue變量和用戶定義的表達式UserExpression,在NCalc你會怎麼做:

myList.Where(elem => new Expression(EstimatedValue.ToString() + UserExpression).Evaluate()); 
+0

我試過Ncalc,但它不工作 –

0

在你的位置,我想創建一個小型規則引擎。

所以

public abstract class ExpressionBase { 
public float value {get;set;} 
} 

public class GreaterThanExpression : ExpressionBase {} 
public class LessThanExpression : ExpressionBase {} 

現在你解析輸入的字符串,你可以建立輸入表達式的列表,然後將它們應用到一個IQueryable你想要的順序。

0

寫LINQ extention方法....

public static IEnumerable<HomeInfo> PassesExpression(this IEnumerable<HomeInfo> homes, ExpressionValue expression) 
{ 
    foreach(HomeInfo home in homes) 
    { 
     bool one, two; 

     if(expression.FirstExpCondition == '>') 
      one = (home.EstimatedValue > expression.FirstDigit); 
     else if(expression.FirstExpCondition == '>=') 
      one = (home.EstimatedValue >= expression.FirstDigit); 
     else if(expression.FirstExpCondition == '<') 
      one = (home.EstimatedValue < expression.FirstDigit); 
     else if(expression.FirstExpCondition == '<=') 
      one = (home.EstimatedValue <= expression.FirstDigit); 

     if(expression.SecondExpCondition == '>') 
      two = (home.EstimatedValue > expression.SecondDigit); 
     else if(expression.SecondExpCondition == '>=') 
      two = (home.EstimatedValue >= expression.SecondDigit); 
     else if(expression.SecondExpCondition == '<') 
      two = (home.EstimatedValue < expression.SecondDigit); 
     else if(expression.SecondExpCondition == '<=') 
      two = (home.EstimatedValue <= expression.SecondDigit); 

     if((expression.ConditionOperator == 'OR' && (one || two)) || (expression.ConditionOperator == 'AND' && (one && two))) 
      yield return home; 
    } 
} 
+0

整個問題是他似乎並不知道如何對代碼段進行編碼。 – Servy

+0

@Servy錯誤地理解了問題I猜測,增加了更多的代碼.. –

0

我通常有兩個值域的文本框。一個用於最小值,一個用於最大值。它們可以是空的,如果不需要限制

int? min = null 
int? max = null; 
int i; 

if (Int32.TryParse(txtMin.Text, out i) min = i; 
if (Int32.TryParse(txtMax.Text, out i) max = i; 

string name = txtName.Text; 

有了這些定義,你可以結合where子句動態

IEnumerable<HomeInfo> result = list; 
if (min.HasValue) result = result.Where(h => h.EstimatedValue >= min.Value); 
if (max.HasValue) result = result.Where(h => h.EstimatedValue <= max.Value); 
if (name != "") 
    result = result.Where(
     h => h.OwnerName.StartsWith(name, StringComparison.OrdinalIgnoreCase) 
    ); 
+0

所以你打算爲每個不同的可能的屬性值做這個,並且每個可能的比較運算符?我認爲它不會很好地擴展。 – Servy

+0

@Servy:我同時修改了我的解決方案。動態組合謂詞。 –

相關問題