首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >筛选列表对象的泛型方法

筛选列表对象的泛型方法
EN

Stack Overflow用户
提问于 2013-12-04 21:42:12
回答 4查看 22.5K关注 0票数 5

我正在尝试创建一个包含三个参数的泛型方法。1)列表集合2)字符串PropertyName 3)字符串FilterString

其思想是,我们传递对象的集合、对象的属性名称和筛选条件,它返回包含FilterString的属性的对象列表。

而且,PropertyName是可选的,所以如果它没有提供,我想返回任何属性中包含FilterString的所有对象。

任何关于这方面的指示都会很有帮助。

我试图让一个方法签名像这样:公共静态列表FilterList(列表集合,字符串FilterString,String FilterString= "")

这样,我就可以从任何地方调用该方法,并传递给它任何列表,它将返回一个筛选过的列表。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-12-04 21:49:23

你可以用LINQ做你想做的事,

代码语言:javascript
复制
var collection = ...
var filteredCollection = 
    collection.Where(item => item.Property == "something").ToList();

否则,你可以尝试反射,

代码语言:javascript
复制
public List<T> Filter<T>(
    List<T> collection, 
    string property, 
    string filterValue)
{
    var filteredCollection = new List<T>();
    foreach (var item in collection)
    {
         // To check multiple properties use,
         // item.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)

         var propertyInfo = 
             item.GetType()
                 .GetProperty(property, BindingFlags.Public | BindingFlags.Instance);
         if (propertyInfo == null)
             throw new NotSupportedException("property given does not exists");             

         var propertyValue = propertyInfo.GetValue(item, null);
         if (propertyValue == filterValue)
             filteredCollection.Add(item);       
    }

    return filteredCollection;
}

此解决方案的问题是,更改属性的名称或拼写错误将导致运行时错误,而不是使用硬类型的实际属性表达式的编译错误。

另外,请注意,基于绑定标志,这将只在publicnon-static属性上工作。您可以通过传递不同的标志来修改这种行为。

票数 8
EN

Stack Overflow用户

发布于 2013-12-04 22:28:31

为此,可以使用反射和动态表达式的组合。我已经把第一次看上去有点长的样本放在一起了。但是,它与您的需求相匹配,并通过以下方式解决这些问题

  • 使用反射查找字符串类型的属性,并匹配属性名称(如果提供)。
  • 创建一个对已标识的所有属性调用string.Contains的表达式。如果已标识了多个属性,则对string.Contains的调用将由或-表达式组合。此筛选器表达式被编译并作为参数传递给Where扩展方法。提供的列表使用表达式进行筛选。

按照这个链接运行示例。

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using System.Linq.Expressions;

public class Test
{
    public static IEnumerable<T> SelectItems<T>(IEnumerable<T> items, string propName, string value)
    {
        IEnumerable<PropertyInfo> props;
        if (!string.IsNullOrEmpty(propName))
            props = new PropertyInfo[] { typeof(T).GetProperty(propName) };
        else
            props = typeof(T).GetProperties();
        props = props.Where(x => x != null && x.PropertyType == typeof(string));
        Expression lastExpr = null;
        ParameterExpression paramExpr = Expression.Parameter(typeof(T), "x");
        ConstantExpression valueExpr = Expression.Constant(value);
        foreach(var prop in props)
        {
            var propExpr = GetPropertyExpression(prop, paramExpr, valueExpr);
            if (lastExpr == null)
                lastExpr = propExpr;
            else
                lastExpr = Expression.MakeBinary(ExpressionType.Or, lastExpr, propExpr);
        }
        if (lastExpr == null)
            return new T[] {};
        var filterExpr = Expression.Lambda(lastExpr, paramExpr);
        return items.Where<T>((Func<T, bool>) filterExpr.Compile());
    }

    private static Expression GetPropertyExpression(PropertyInfo prop, ParameterExpression paramExpr, ConstantExpression valueExpr)
    {
        var memberAcc = Expression.MakeMemberAccess(paramExpr, prop);
        var containsMember = typeof(string).GetMethod("Contains");
        return Expression.Call(memberAcc, containsMember, valueExpr);
    }

    class TestClass
    {
        public string SomeProp { get; set; }
        public string SomeOtherProp { get; set; }
    }

    public static void Main()
    {
        var data = new TestClass[] {
            new TestClass() { SomeProp = "AAA", SomeOtherProp = "BBB" }, 
            new TestClass() { SomeProp = "BBB", SomeOtherProp = "CCC" }, 
            new TestClass() { SomeProp = "CCC", SomeOtherProp = "AAA" }, 
        };
        var result = SelectItems(data, "", "A");
        foreach(var item in result)
            Console.WriteLine(item.SomeProp);
    }
}

与完全基于反射的方法相比,这种方法只组合了一次筛选器表达式并编译它,因此我期望性能得到(小的)改善。

票数 5
EN

Stack Overflow用户

发布于 2013-12-04 22:02:23

例如,在给定动态LINQ的情况下,应该使用SomeClass

代码语言:javascript
复制
public class SomeClass 
{
    public int SomeField { get; set; }
}
List<SomeClass> list = new List<SomeClass>() { new SomeClass() { SomeField = 2 } };

然后:

代码语言:javascript
复制
var temp = list.AsQueryable().Where("SomeField == 1").Select("it");
var result= temp .Cast<SomeClass>().ToList();

因此,您的函数将更加简单,将属性名称和过滤器合并到一个参数中:

代码语言:javascript
复制
public List<T> Filter<T>(List<T> list, string filter)
{
    var temp = list.AsQueryable().Where(filter).Select("it");
    return temp.Cast<T>().ToList();
}

您可以提供不同的过滤器,例如"SomeField > 4 && SomeField < 10"等。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20386634

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档