如何在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) { }
我需要关注的事情
- 在ProcessData方法内部我想过滤具有isProcessed标志的项目为“True”。
- 此外,我想迭代此集合,并需要为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解决方案
此方法将迭代集合,根据propertyName
和filterValue
过滤,并使用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); });
但仍有一个区别。 因为如果你有一个包含元素A
和B
的集合,就像这样:(我在这种情况下使用了一个示例构造函数)
List
您必须将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); } } }