C# 当类型确定具有特定属性时,从集合中移除项的通用方法
考虑一下这段代码 distinctBrandIds是long类型的集合 SomeClass具有BrandId属性 当BrandId等于BrandYesNoDictionary中的BrandId键且值为false时,将删除CollectionOsomeClass中的项C# 当类型确定具有特定属性时,从集合中移除项的通用方法,c#,C#,考虑一下这段代码 distinctBrandIds是long类型的集合 SomeClass具有BrandId属性 当BrandId等于BrandYesNoDictionary中的BrandId键且值为false时,将删除CollectionOsomeClass中的项 distinctBrandIds.ForEach((v) => { if (!(BrandYesNo[v])) { CollectionOfSomeClass.RemoveAll(sc =>
distinctBrandIds.ForEach((v) =>
{
if (!(BrandYesNo[v]))
{
CollectionOfSomeClass.RemoveAll(sc => sc.BrandId == v);
}
});
在其他地方,相同的代码会在其他类型的集合中重复,而不是在CollectionOfSomeClass中重复。
常见的是,另一个集合所使用的类型也有BrandId。所以检查总是在BrandId属性上
为了创建一个通用方法,有人建议使用反射,在这些方面我有以下建议:
public void RemoveItemsFromList<T>(List<T> CollectionOfSomeClass, List<long> distinctBrandIds, object propertyToCheck) where T : class
{
distinctBrandIds.ForEach((v) =>
{
if (!(BrandYesNo[v]))
{
CollectionOfSomeClass.RemoveAll((rd) => {
PropertyInfo pi = typeof(T).GetProperty("BrandId");
pi.GetValue(rd) == v;
});
}
});
}
谓词不正确
我该如何处理这件事
提前谢谢
公认的答案
起初情况并非如此,但我确信CodeCaster解决方案具有强大的功能。为了说明我的评论,以下代码应该可以工作,但速度会很慢:
public void RemoveItemsFromList<T>(List<T> CollectionOfSomeClass,
List<long> distinctBrandIds)
where T : class
{
PropertyInfo pi = typeof(T).GetProperty("BrandId");
distinctBrandIds.ForEach(v =>
{
if (!(BrandYesNo[v]))
{
CollectionOfSomeClass.RemoveAll(rd => ((long)pi.GetValue(rd) == v));
}
});
}
或者使用相等的
请注意,仅当您无权访问类代码或无法修改它时,才应使用此代码。如果不是这样,@CodeMaster的解决方案更安全、更快。为了说明我的评论,以下代码应该可以工作,但速度会很慢:
public void RemoveItemsFromList<T>(List<T> CollectionOfSomeClass,
List<long> distinctBrandIds)
where T : class
{
PropertyInfo pi = typeof(T).GetProperty("BrandId");
distinctBrandIds.ForEach(v =>
{
if (!(BrandYesNo[v]))
{
CollectionOfSomeClass.RemoveAll(rd => ((long)pi.GetValue(rd) == v));
}
});
}
或者使用相等的
请注意,仅当您无权访问类代码或无法修改它时,才应使用此代码。如果不是这种情况,@CodeMaster的解决方案更安全、更快。如果您知道并控制此方法要处理的类型,则无需在此进行反射。照你说的 常见的是,另一个集合所使用的类型也有BrandId。所以检查总是在BrandId属性上 创建一个接口:
public interface IBrand
{
long BrandId { get; }
}
将其应用于适当的类别:
public class SomeClass : IBrand
{ ... }
并修改您的约束:
public void RemoveItemsFromList<T>(List<T> CollectionOfSomeClass, List<long> distinctBrandIds)
where T : IBrand
{
distinctBrandIds.ForEach((v) =>
{
if (!(BrandYesNo[v]))
{
CollectionOfSomeClass.RemoveAll(rd => rd.BrandId == v);
}
}
}
如果您知道并控制此方法要处理的类型,那么这里不需要反射。照你说的 常见的是,另一个集合所使用的类型也有BrandId。所以检查总是在BrandId属性上 创建一个接口:
public interface IBrand
{
long BrandId { get; }
}
将其应用于适当的类别:
public class SomeClass : IBrand
{ ... }
并修改您的约束:
public void RemoveItemsFromList<T>(List<T> CollectionOfSomeClass, List<long> distinctBrandIds)
where T : IBrand
{
distinctBrandIds.ForEach((v) =>
{
if (!(BrandYesNo[v]))
{
CollectionOfSomeClass.RemoveAll(rd => rd.BrandId == v);
}
}
}
与s的答案类似,您可以使用反射,但可以使用字典对其进行缓存:
//存储获取具有BrandId属性的对象的函数
//并返回转换为long的BrandId属性的值
私有静态只读字典_getBrandId=new;
public void RemoveItemsFromListList CollectionOfSomeClass,
列出distinctBrandIds
T:在哪里上课
{
//检查函数是否已缓存
如果!\u getBrandId.TryGetValuetypeofT,则输出变量getBrandId
{
//使用表达式树创建lambda
var lambda=表达式.lambda
表达式。转换
表达式.属性
表达式。参数类型对象,
布兰迪,
长的类型,
目标
//将其存储到缓存中
getBrandId=\u getBrandId[typeofT]=lambda.Compile;
}
distinctBrandIds.ForEachv=>
{
如果BrandYesNo[v]继续;
CollectionOfSomeClass.RemoveAllrd=>getBrandIdrd==v;
};
}
与s的答案类似,您可以使用反射,但可以使用字典对其进行缓存:
//存储获取具有BrandId属性的对象的函数
//并返回转换为long的BrandId属性的值
私有静态只读字典_getBrandId=new;
public void RemoveItemsFromListList CollectionOfSomeClass,
列出distinctBrandIds
T:在哪里上课
{
//检查函数是否已缓存
如果!\u getBrandId.TryGetValuetypeofT,则输出变量getBrandId
{
//使用表达式树创建lambda
var lambda=表达式.lambda
表达式。转换
表达式.属性
表达式。参数类型对象,
布兰迪,
长的类型,
目标
//将其存储到缓存中
getBrandId=\u getBrandId[typeofT]=lambda.Compile;
}
distinctBrandIds.ForEachv=>
{
如果BrandYesNo[v]继续;
CollectionOfSomeClass.RemoveAllrd=>getBrandIdrd==v;
};
}
您也可以使用dynamic,但您的解决方案会遇到相同的问题:对性能的影响。是否可以使类实现具有BrandId属性的公共接口?虽然引入接口是一个好主意,但我正在处理遗留代码,更改的地方太多。请注意,如果因为GetValue返回对象,代码也会失败。因为==是在编译时绑定的,所以将使用对象比较,而不是您想要的值。您可以通过将GetValue强制转换为long来实现,如果BrandId在所有类中都是long,那么这将起作用。对许多地方的更改并不是牺牲类型安全IMHO的好借口。不恰当地使用反射
这可能会使您的代码难以阅读和理解。您也可以使用dynamic,但您的解决方案也会遇到同样的问题:对性能的影响。是否可以使类实现具有BrandId属性的公共接口?虽然引入接口是一个好主意,但我正在处理遗留代码,更改的地方太多。请注意,如果因为GetValue返回对象,代码也会失败。因为==是在编译时绑定的,所以将使用对象比较,而不是您想要的值。您可以通过将GetValue强制转换为long来实现,如果BrandId在所有类中都是long,那么这将起作用。对许多地方的更改并不是牺牲类型安全IMHO的好借口。不适当地使用反射可能会使您的代码难以阅读和理解。根据OP的评论,他正在处理遗留代码,因此这可能是不可能的。但是,如果可能的话,这是最好的答案。对我来说,在少数类中添加一个接口似乎比使用反射的入侵性要小一些,因为以后可能会出现故障,但这正是我的观点。@CodeCaster我认为它更具入侵性,但更安全。我在下面的回答是在OP确认他/她不能选择修改课程后发布的。如果不是这样的话,您的解决方案肯定是可行的。@vc74是的,侵入性较小并没有真正实现我的意思,即添加一个接口不会破坏其他任何东西,同时为您提供编译时安全性,而不是使用反射。我们不应该害怕修改现有的类。可以是多少,5,10,25?OP将检查他们的代码,并在某些地方添加此方法调用,只需花很少的努力就可以定义使用它们的类,并实现接口。根据OP的评论,他正在处理遗留代码,因此这可能是不可能的。但是,如果可能的话,这是最好的答案。对我来说,在少数类中添加一个接口似乎比使用反射的入侵性要小一些,因为以后可能会出现故障,但这正是我的观点。@CodeCaster我认为它更具入侵性,但更安全。我在下面的回答是在OP确认他/她不能选择修改课程后发布的。如果不是这样的话,您的解决方案肯定是可行的。@vc74是的,侵入性较小并没有真正实现我的意思,即添加一个接口不会破坏其他任何东西,同时为您提供编译时安全性,而不是使用反射。我们不应该害怕修改现有的类。可以是多少,5,10,25?OP将遍历他们的代码,并在某些地方添加此方法调用,只需花很少的精力就可以定义使用它们的类,并实现接口。