如何在generics方法中过滤集合

我有两个类,它具有以下属性

Class A { public int CustID { get; set; } public bool isProcessed { get; set; } } Class B { public int EmpId{ get; set; } public bool isProcessed { get; set; } } 

我创建了一个接受所有这些类的generics方法。’isProcessed’属性在这两个类中都很常见。

 public void ProceesData(IList param1, string date1) { } 

我需要关注的事情

  1. 在ProcessData方法内部我想过滤具有isProcessed标志的项目为“True”。
  2. 此外,我想迭代此集合,并需要为IsProcessed属性设置值。

注意:我更喜欢使用reflection的解决方案,因为属性名称是常量(即“IsProcessed”)

任何人都可以帮助这个。

最简单的方法是确保两个类都实现一个公共接口并约束您的generics方法。 例如:

 public interface IProcessable { bool isProcessed { get; set; } } public class A : IProcessable { public int CustID { get; set; } public bool isProcessed { get; set; } } public class B : IProcessable { public int EmpId { get; set; } public bool isProcessed { get; set; } } 

现在你的方法看起来像这样:

 public void ProceesData(IList param1, string date1) where T : IProcessable // <-- generic constraint added { foreach (var element in param1) { element.isProcessed = true; } } 

如果您不能使用接口或属性名称变得更有用的另一个选项是将Action作为参数传递给您的方法。 例如:

 public void ProceesData(IList param1, string date1, Action func) { foreach (var element in param1) { func(element); } } 

并称之为:

 ProceesData(list, "", x => x.isProcessed = true); 

创建一个接口,如IProcessData ,它包含一个布尔属性IsProcessed 。 让两个类都实现此接口。 更改ProcessData方法,使其不再具有通用符号( )并接受IList 。 然后对param1数据执行过滤和迭代。

注意:我更喜欢使用reflection解决方案

此方法将迭代集合,根据propertyNamefilterValue过滤,并使用reflection将值设置为newValue

 public void ProceesData(IList param1, string date1, string propertyName, object filterValue, object newValue) { PropertyInfo pi = typeof(T).GetProperty(propertyName); object value; for (int i = param1.Count; i <= 0; i--) { value = pi.GetValue(param1[i]); if (value.Equals(filterValue)) { pi.SetValue(param1[i], newValue); } } } 

你可以这样称呼它:

 ProceesData(a_list, "", "isProcessed", false, true); 

免责声明:

虽然这是可能的。 它远非拯救。 如果你交出错误的属性名称,它将失败! 我建议使用@DavidG移交Action委托的第二种方法。 这将使整个处理更加健全,不易出错。 我建议在这里使用正常的反向for循环,因为这甚至允许你从你的集合中删除项目。

 public static void ProceesData(IList param1, string date1, Action func) { for (int i = param1.Count; i <= 0; i--) { func(param1[i]); } } 

这个调用会给你相同的结果:

 ProceesData(a_list, "", (x)=> { if (!x.isProcessed) x.isProcessed = true; }); 

通过这种方法可以更灵活,因为您可以在每次调用时决定此方法应该执行的操作。 您甚至可以从集合中删除已处理的项目:

 ProceesData(a_list, "", (x)=> { if (!x.isProcessed) a_list.Remove(x); }); 

但仍有一个区别。 因为如果你有一个包含元素AB的集合,就像这样:(我在这种情况下使用了一个示例构造函数)

 List obj_list = new List() { new A(1, false), new B(2, true), new A(3, false), new B(4, false), }; 

您必须将dynamic数据类型用于Action重载:

 ProceesData(obj_list, "", (x) => { if (!x.isProcessed) obj_list.Remove(x); }); 

对于reflection做事方式,您需要在每次迭代时检查类型。 这会增加处理时间。

 public static void ProceesData(IList param1, string date1, string propertyName, object filterValue, object newValue) { for (int i = param1.Count-1; i >= 0; i--) { PropertyInfo pi = param1[i].GetType().GetProperty(propertyName); object value; value = pi.GetValue(param1[i]); if (value.Equals(filterValue)) { pi.SetValue(param1[i], newValue); } } }