2012-10-01 43 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:我同时修改了我的解决方案。动态组合谓词。 –

相关问题