如何在泛型方法中过滤集合
How to filter a collection inside a generic method
我有两个 class 具有以下属性
Class A
{
public int CustID { get; set; }
public bool isProcessed { get; set; }
}
Class B
{
public int EmpId{ get; set; }
public bool isProcessed { get; set; }
}
我创建了一个接受所有这些 classes 的通用方法。'isProcessed' 属性 在这两个 classes 中都很常见。
public void ProceesData<T>(IList<T> param1, string date1)
{
}
我需要以下东西
- 在 ProcessData 方法中,我想过滤具有
isProcessed 标志是 "True".
- 另外我想迭代这个集合并需要为 IsProcessed 设置值 属性。
注意:我更喜欢使用反射的解决方案,因为 属性 名称是常量(即 "IsProcessed")
谁能帮忙解决这个问题。
创建一个接口,如 IProcessData
,其中包含布尔值 属性、IsProcessed
。让两个 类 实现这个接口。更改您的 ProcessData
方法,使其不再具有通用符号 (<T>
) 并接受 IList<IProcessData>
。然后对 param1 数据执行过滤和迭代。
最简单的方法是确保 类 实现一个公共接口并限制您的通用方法。例如:
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<T>(IList<T> param1, string date1)
where T : IProcessable // <-- generic constraint added
{
foreach (var element in param1)
{
element.isProcessed = true;
}
}
如果您不能使用接口或 属性 名称不同,另一个更有用的选项是将 Action<T>
作为参数传递给您的方法。例如:
public void ProceesData<T>(IList<T> param1, string date1, Action<T> func)
{
foreach (var element in param1)
{
func(element);
}
}
并这样称呼它:
ProceesData<A>(list, "", x => x.isProcessed = true);
Note: I am preferring solution using reflection
此方法将迭代 collection,根据 propertyName
和 filterValue
进行过滤,并使用反射将值设置为 newValue
:
public void ProceesData<T>(IList<T> 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>(a_list, "", "isProcessed", false, true);
免责声明:
虽然这是可能的。离得救还很远。如果你交错 属性 名字,它将失败!我建议通过@DavidG 移交 Action
委托来使用第二种方法。这样会让整个处理过程更加完善,不容易出错。我建议在这里使用正常的反向 for-loop,因为这甚至可以让你从 collection.
中删除项目
public static void ProceesData<T>(IList<T> param1, string date1, Action<T> func)
{
for (int i = param1.Count; i <= 0; i--)
{
func(param1[i]);
}
}
这个调用会给你同样的结果:
ProceesData<A>(a_list, "", (x)=> { if (!x.isProcessed) x.isProcessed = true; });
通过这种方法你会变得更加灵活,因为你可以在每次调用时决定这个方法应该做什么。您甚至可以从 collection:
中删除已处理的项目
ProceesData<A>(a_list, "", (x)=> { if (!x.isProcessed) a_list.Remove(x); });
不过还是有一点不同。因为如果你有一个包含元素 A
和 B
的 collection,就像这样:(我在这种情况下使用了一个示例性构造函数)
List<object> obj_list = new List<object>()
{
new A(1, false),
new B(2, true),
new A(3, false),
new B(4, false),
};
您必须为 Action
重载使用 dynamic
数据类型:
ProceesData<dynamic>(obj_list, "", (x) => { if (!x.isProcessed) obj_list.Remove(x); });
并且对于做事的反射方式,您需要在每次迭代时检查类型。这会增加处理时间。
public static void ProceesData<T>(IList<T> 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);
}
}
}
我有两个 class 具有以下属性
Class A
{
public int CustID { get; set; }
public bool isProcessed { get; set; }
}
Class B
{
public int EmpId{ get; set; }
public bool isProcessed { get; set; }
}
我创建了一个接受所有这些 classes 的通用方法。'isProcessed' 属性 在这两个 classes 中都很常见。
public void ProceesData<T>(IList<T> param1, string date1)
{
}
我需要以下东西
- 在 ProcessData 方法中,我想过滤具有 isProcessed 标志是 "True".
- 另外我想迭代这个集合并需要为 IsProcessed 设置值 属性。
注意:我更喜欢使用反射的解决方案,因为 属性 名称是常量(即 "IsProcessed")
谁能帮忙解决这个问题。
创建一个接口,如 IProcessData
,其中包含布尔值 属性、IsProcessed
。让两个 类 实现这个接口。更改您的 ProcessData
方法,使其不再具有通用符号 (<T>
) 并接受 IList<IProcessData>
。然后对 param1 数据执行过滤和迭代。
最简单的方法是确保 类 实现一个公共接口并限制您的通用方法。例如:
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<T>(IList<T> param1, string date1)
where T : IProcessable // <-- generic constraint added
{
foreach (var element in param1)
{
element.isProcessed = true;
}
}
如果您不能使用接口或 属性 名称不同,另一个更有用的选项是将 Action<T>
作为参数传递给您的方法。例如:
public void ProceesData<T>(IList<T> param1, string date1, Action<T> func)
{
foreach (var element in param1)
{
func(element);
}
}
并这样称呼它:
ProceesData<A>(list, "", x => x.isProcessed = true);
Note: I am preferring solution using reflection
此方法将迭代 collection,根据 propertyName
和 filterValue
进行过滤,并使用反射将值设置为 newValue
:
public void ProceesData<T>(IList<T> 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>(a_list, "", "isProcessed", false, true);
免责声明:
虽然这是可能的。离得救还很远。如果你交错 属性 名字,它将失败!我建议通过@DavidG 移交 Action
委托来使用第二种方法。这样会让整个处理过程更加完善,不容易出错。我建议在这里使用正常的反向 for-loop,因为这甚至可以让你从 collection.
public static void ProceesData<T>(IList<T> param1, string date1, Action<T> func)
{
for (int i = param1.Count; i <= 0; i--)
{
func(param1[i]);
}
}
这个调用会给你同样的结果:
ProceesData<A>(a_list, "", (x)=> { if (!x.isProcessed) x.isProcessed = true; });
通过这种方法你会变得更加灵活,因为你可以在每次调用时决定这个方法应该做什么。您甚至可以从 collection:
中删除已处理的项目ProceesData<A>(a_list, "", (x)=> { if (!x.isProcessed) a_list.Remove(x); });
不过还是有一点不同。因为如果你有一个包含元素 A
和 B
的 collection,就像这样:(我在这种情况下使用了一个示例性构造函数)
List<object> obj_list = new List<object>()
{
new A(1, false),
new B(2, true),
new A(3, false),
new B(4, false),
};
您必须为 Action
重载使用 dynamic
数据类型:
ProceesData<dynamic>(obj_list, "", (x) => { if (!x.isProcessed) obj_list.Remove(x); });
并且对于做事的反射方式,您需要在每次迭代时检查类型。这会增加处理时间。
public static void ProceesData<T>(IList<T> 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);
}
}
}