筛选列表对象的通用方法

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

我们的想法是传递一个对象集合,对象属性的名称和过滤条件,它返回一个对象列表,其中属性包含FilterString。

此外,PropertyName是可选的,因此如果未提供,我想在任何属性中返回包含FilterString的所有对象。

任何关于此的指针都会非常有用。

我想尝试这样的方法签名:public static List FilterList(List collection,String FilterString,String Property =“”)

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

您可以使用LINQ执行您想要的操作,因此,

var collection = ... var filteredCollection = collection.Where(item => item.Property == "something").ToList(); 

否则,你可以尝试reflection,

 public List Filter( List collection, string property, string filterValue) { var filteredCollection = new List(); 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; } 

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

另外,请注意,基于绑定标志,这仅适用于public non-static属性。 您可以通过传递不同的标志来修改此类行为。

您应该使用Dynamic LINQ ,例如,给定SomeClass

 public class SomeClass { public int SomeField { get; set; } } List list = new List() { new SomeClass() { SomeField = 2 } }; 

然后:

 var temp = list.AsQueryable().Where("SomeField == 1").Select("it"); var result= temp .Cast().ToList(); 

所以你的函数会更简单,属性名称和filter合并为一个参数:

 public List Filter(List list, string filter) { var temp = list.AsQueryable().Where(filter).Select("it"); return temp.Cast().ToList(); } 

并且您可以提供不同的filter,例如"SomeField > 4 && SomeField < 10"等。

您可以为此使用reflection和动态表达式的组合。 我把第一眼看起来有点长的样本放在一起。 但是,它符合您的要求并通过以下方式解决

  • 使用reflection来查找字符串类型的属性并匹配属性名称 – 如果提供的话。
  • 创建一个在已标识的所有属性上调用string.Contains的表达式。 如果已识别多个属性,则对String.Contains的调用由Or-expressions组合。 编译此filter表达式并将其作为参数传递给Where扩展方法。 使用表达式过滤提供的列表。

请点击此链接运行示例。

 using System; using System.Collections.Generic; using System.Reflection; using System.Linq; using System.Linq.Expressions; public class Test { public static IEnumerable SelectItems(IEnumerable items, string propName, string value) { IEnumerable 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((Func) 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); } } 

与基于完全reflection的方法相比,这个方法只组装filter表达式一次并编译它,因此我希望(小)性能改进。

使用Markus解决方案时,只有在所有String属性都不为null时才会起作用。 为了确保您可以这样做:

 class TestClass { private string _someProp { get; set; } public string SomeProp { get { if(string.IsNullOrEmpty(_someProp) { _someProp = ""; } return _someProp; } set { _someProp = value; } } private string _someOtherProp { get; set; } public string SomeOtherProp { get { if(string.IsNullOrEmpty(_someOtherProp) { _someOtherProp = ""; } return _someOtherProp; } set { _someOtherProp = value; } } } 

由于我的代表不到50我不能发表评论;)