我想要一个接受对象列表的方法,然后是“过滤器对象”(与对象列表类型相同)。我能够(低效率地)小规模地做到这一点,但也相当固定-我希望它是一种通用方法,因此我可以传入类型以便将其应用于任何事物。
示例:
public class Program {
public void Main(string[] args) {
var listOfObjects = new List<MyClass> {
new MyClass { ID = 1, Name = "Object 1" },
new MyClass { ID = 2, Name = "Object 2" },
new MyClass { ID = 3, Name = "Object 2" }
};
var filter = new MyClass { Name = "Object 2" };
// Should return only the first object in the list, since
// the filter's Name = "Object 2", all items in the list
// where the property equals "Object 2" will be filtered out
var filteredList = FilterObjects(listOfObjects, filter);
}
}
public class MyClass {
public int ID { get; set; }
public string Name { get; set; }
}
public class MyTest {
public List<MyClass> FilterObjects(List<MyClass> objects, MyClass filter) {
// first check if the filter is just an empty new instance
// if a user passes in an empty filter then they are not
// filtering anything, therefore
if (filter == new MyClass()) return objects;
var filteredList = new List<MyClass>();
foreach (var item in objects) {
// if this item passes the test for the filter
// (check if any of the properties are equal to the
// filter properties - if so, then this item is not
// is not a match, and we cannot add it to the list)
if (item.ID != filter.ID && item.Name != filter.Name)
filteredList.Add(item);
// What I want is a faster and more consolidated way of
// checking all the properties.
}
return filteredList;
}
}
编辑:有什么方法也可以使用反射吗?
EDIT2:仅想澄清一下,我的示例只是一个简单的模板。我正在使用具有20多个属性的对象,并且希望在可能的情况下不必做出巨大的if语句。
EDIT3:我还要提及用户传递的过滤器对象可能不完整,例如它们可以传入没有ID的MyClass
对象(只是Name属性),因为当到达我的Controller时,该MyClass对象将自动用默认值填充ID。我可以通过创建MyClass的新实例-new MyClass()
来检查它是否为默认值,对于每个属性,如果它等于默认值,则可以忽略该属性以进行过滤,因为用户不希望这样属性已过滤。但是从更大的角度考虑这个概念,我拥有20多个属性,用户想要过滤掉所有对象,但只想使用其中的3个属性进行过滤。其他17个以上的属性将不进行相等性检查。
答案 0 :(得分:2)
听起来像您想要的是通用语句。
这不是超级简单,但是类似这样的方法应该起作用:
public static IEnumerable<T> Filter<T>(this IEnumerable<T> results, Filter filter)
{
var types = results.GetType().GetProperties();
foreach (var filter in filter.Filters)
{
Type type = results.GetType();
filter.ColumnName = filter.ColumnName.Replace(" ", "");
var pred = BuildPredicate<T>(filter.ColumnName, filter.FilterValue);
if (filter.ColumnName != null && filter.FilterValue != null)
{
results = results.Where(w =>
{
return w.GetType().GetProperty(filter.ColumnName).GetValue(w, null).ToString().ToLowerInvariant().Contains(filter.FilterValue.ToLowerInvariant());
});
}
}
return results;
}
过滤器对象看起来像:
public class Filter
{
public string ColumnName {get; set; }
public string Value { get; set; }
//Other properties for Asc / Desc and more
}
然后在诸如List或List之类的任何List上,您基本上都会这样做:
var results = MyList.Filter(new Filter() { ColumnName = "LastName"; Value = "Smith" });
将其转换为一个函数,如果手动键入该函数将类似于:
var results = MyList.Where(w => w.LastName == "Smith");
这个例子很粗糙,没有针对初学者的类型检查。
答案 1 :(得分:0)
为什么不仅仅使用System.Generic.Collections
库中已经存在的方法。
var filteredList= new List<MyClass>(listOfObjects);
filteredList.RemoveWhere(n => n.Name == "Object 2");
如果要使用其他类作为过滤器:
MyClass filter = new MyClass() {Name = "Object 2", Id=2 };
var filteredList= new List<MyClass>(listOfObjects);
filteredList.RemoveWhere(n => (n.Name == filter.Name || n.Id == filter.Id)); // you can modify predicate based on whatever you wish to compare
答案 2 :(得分:0)
我将使用自定义的IsMatch
方法:
static bool IsMatch (MyClass toTest, MyClass filter)
{
if (filter.Prop1 != null // or whatever value means "skip this property"
&& filter.Prop1 == toTest.Prop1)
return true;
if (filter.Prop2 != null & filter.Prop2 == toTest.Prop2)
return true;
...
return false;
}
然后让Linq为您查找:
List<MyClass> filtered = listOfObjects.Where(x => !IsMatch(x, filter)).ToList();
单元测试(带有反射)确保此方法始终是最新的,现在和将来都要检查所有属性,这有助于在向类添加属性时不引入错误