【问题标题】:Filtering on template list with property name as string使用属性名称作为字符串过滤模板列表
【发布时间】:2012-12-28 09:34:05
【问题描述】:

您好,我必须对泛型类应用过滤器。示例类如下

public class Sample<T>
{
    List<T> sourceList = new List<T>();

    public void applyFilter(string propertyName , EnumOperator operator , object value)
    {

    }
}

在这里,我想使用 linq 或动态 linq 实现过滤器,但没有得到任何积极的方向来实现此功能。

请给我一些积极的方向,以便我可以实现这个功能。

谢谢。

【问题讨论】:

  • 为什么你有一个泛型类而不做任何泛型?
  • 我采用了泛型类,因为我使用的是 T 类型的绑定源,其中数据来自不同的表,我必须对其应用过滤器。

标签: c# .net linq generics linq-to-objects


【解决方案1】:

我建议返回一个过滤列表而不是修改源,而且字符串“operator”是一个 C# 关键字,所以方法的签名可以是:

public List<T> ApplyFilter(string propertyName, EnumOperator operatorType, object value)
{
   ....
}

我假设EnumOperatorenum,其值如下:

public enum EnumOperator
{
   Equal,
   NotEqual,
   Bigger,
   Smaller
}

并且您有一些方法可以检查运算符的值是通过还是未通过测试,类似于:

public static class OperatorEvaluator
{ 
  public static bool Evaluate(EnumOperator operatorType, object first, object second)
  {
    ...
  }
}

鉴于此,您可以执行以下操作:

public List<T> ApplyFilter(string propertyName , EnumOperator operatorType, object value)
{
  PropertyInfo pi = typeof(T).GetProperty(propertyName);
  List<T> result = sourceList.Where(item => { 
    var propValue = pi.GetValue(item, null);
    return OperatorEvaluator.Evaluate(operatorType, propValue, value);
  }).ToList();
  return result;
}

也就是说,您始终可以使用 LINQ 的方法过滤几乎所有内容,而无需借助反射。

【讨论】:

    【解决方案2】:

    要使用动态表达式(作为字符串)进行查询,您可以使用 Microsoft 的 Dynamic LINQ by Scott Gu

    Samples

    支持以下操作
    1. 选择
    2.在哪里
    3. OrderBy
    4. 跳过
    5. 拍摄
    6. 分组方式

    以上所有操作都以字符串为参数。

    它还具有非常易于使用的小型表达式语言(用于构建选择器/谓词/等)。

    例子:

    var query =
    db.Customers.
    Where("City = @0 and Orders.Count >= @1", "London", 10).
    OrderBy("CompanyName").
    Select("new(CompanyName as Name, Phone)");  
    

    【讨论】:

      【解决方案3】:

      这里我给你一个示例,如何在List&lt;T&gt;项目上使用LINQ实现过滤..

      public class clsCountry
      {
          public string _CountryCode;
          public string _CountryName;
          //
          public clsCountry(string strCode, string strName)
          {
              this._CountryCode = strCode;
              this._CountryName = strName;
          }
          //
          public string CountryCode
          {
              get {return _CountryCode;}
              set {_CountryCode = value;}
          }
          //
          public string CountryName
          {
              get { return _CountryName; }
              set { _CountryName = value; }
          }
      }
      

      现在,让我们根据clsCountry 类创建一个对象列表,并将它们存储在List&lt;T&gt; 对象中。

      List<clsCountry> lstCountry = new List<clsCountry>();
      lstCountry.Add(new clsCountry("USA", "United States"));
      lstCountry.Add(new clsCountry("UK", "United Kingdom"));
      lstCountry.Add(new clsCountry("IND", "India"));
      

      接下来,我们将List&lt;T&gt;对象lstCountry绑定到一个名为drpCountry的DropDownList控件,如下所示:

      drpCountry.DataSource = lstCountry;
      drpCountry.DataValueField = "CountryCode";
      drpCountry.DataTextField = "CountryName";
      drpCountry.DataBind();
      

      现在,使用 LINQ 过滤来自 lstCountry 对象的数据,并将过滤后的列表绑定到下拉控件drpCountry。

       var filteredCountries = from c in lstCountry
                              where c.CountryName.StartsWith("U")
                              select c;
      
      drpCountry.DataSource = filteredCountries;
      drpCountry.DataValueField = "CountryCode";
      drpCountry.DataTextField = "CountryName";
      drpCountry.DataBind();
      

      现在下拉控件将​​只有 2 个项目

      美国
      英国

      现在将这些技术应用到您的案例中......

      【讨论】:

        【解决方案4】:

        您可以使用反射来检索属性值,您可以在操作员上使用简单的switch 语句来执行过滤:

        public IEnumerable<T> ApplyFilter(string propertyName, EnumOperator op, object value)
        {
            foreach (T item in sourceList)
            {
                object propertyValue = GetPropertyValue(item, propertyName);
                if (ApplyOperator(item, propertyValue, op, value)
                {
                    yield return item;
                }
            }
        }
        
        private object GetPropertyValue(object item, string propertyName)
        {
            PropertyInfo property = item.GetType().GetProperty(propertyName);
            //TODO handle null
            return property.GetValue();
        }
        
        private bool ApplyOperator(object propertyValue, EnumOperator op, object value)
        {
            switch (op)
            {
                case EnumOperator.Equals:
                    return propertyValue.Equals(value);
                //TODO other operators
                default:
                    throw new UnsupportedEnumException(op);
            }
        }
        

        (优化是在循环外查找PropertyInfo。)

        【讨论】:

          猜你喜欢
          • 2016-01-16
          • 2023-03-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-02-08
          • 1970-01-01
          • 2017-01-31
          • 1970-01-01
          相关资源
          最近更新 更多