C# c如何在通用IEnumerable上使用.Contains
我试图创建一个通用方法,用于混合基于属性的对象列表。(可选)可以提供列表对象列表以将某些组合并在一起。作为一个非泛型方法,当我手动编写属性代码时,这种方法可以很好地工作 方法头:C# c如何在通用IEnumerable上使用.Contains,c#,linq,generics,ienumerable,contains,C#,Linq,Generics,Ienumerable,Contains,我试图创建一个通用方法,用于混合基于属性的对象列表。(可选)可以提供列表对象列表以将某些组合并在一起。作为一个非泛型方法,当我手动编写属性代码时,这种方法可以很好地工作 方法头: public static IEnumerable<T> MixObjectsByProperty<T>( IEnumerable<T> objects, string propertyName, IEnumerable<IEnumerable<T
public static IEnumerable<T> MixObjectsByProperty<T>(
IEnumerable<T> objects,
string propertyName,
IEnumerable<IEnumerable<T>> groupsToMergeByProperty = null)
如您所见,我在IEnumerable上使用contains方法时遇到问题,因为propertyInfo.GetValueitem,null返回一个对象。我尝试了各种铸造尝试和使用。任何替代,但我碰到了一堵砖墙:
任何帮助都会很好,谢谢
另外,如果您需要更多信息,请告诉我,但我想,本质上,我需要知道的是如何使用.Contains using
将它们设置为相同的类型?自定义IEqualityComparer
我试过各种各样的施法尝试
你试过这个吗
.FirstOrDefault(ids => ids.Contains((T)propertyInfo.GetValue(item, null)))
由于ids是IGrouping类型,而TElement在您的案例中是T类型,因此将属性的值强制转换为T将允许进行比较。好的,因此我最终破解了它。我需要在我的泛型方法头/签名中添加更多细节
public static IEnumerable<T> MixObjectsByProperty<T, U>(
IEnumerable<T> objects, string propertyName, IEnumerable<IEnumerable<U>> groupsToMergeByProperty = null)
where T : class
where U : class
{
...
没有看到整个方法,因为您的类型签名清楚地表明它不是整个方法,下面是一个示例实现:
public class Ext
{
public static List<T[]> MixObjectsByProperty<T, TProp, U>(
IEnumerable<T> source,
Expression<Func<T, TProp>> property,
IEnumerable<IEnumerable<U>> groupsToMix = null)
where T : class
where U : TProp
{
var prop = (PropertyInfo)(property.Body as MemberExpression)?.Member;
if (prop == null) throw new ArgumentException("Couldn't determine property");
var accessor = property.Compile();
var groups =
from item in source
let value = (U)accessor(item)
group item by
groupsToMix.FirstOrDefault((ids => ids.Contains(value)))
into itemGroup
select itemGroup.ToArray();
return groups.ToList();
}
}
出于对上帝的爱,停止传递财产名称和使用反射,Linq的其余部分使用华丽的表达系统,你也应该这样做 为什么不将GetValue的结果强制转换为T呢?如果您可以将T约束到基类型或接口,这将有很大帮助。除非您将T强制转换为特定类型,否则就不能了。为什么要传递属性名?为什么不像所有LINQ方法一样传递表达式,例如使用Func-propGetter并传递它=>it.PropName作为参数值。或者将整个条件作为表达式传递?我试过了,但有趣的是,我早些时候又试了一次,再做一些调整,我就让它工作了!:我现在就发布答案,这样其他人可以看到我做了什么,等等。好的,哇,冷静:P谢谢你的输入,看起来不错-我没有意识到这一点。然而,你能让你的linq作为列表返回吗?然后我就可以完全测试这个潜在的解决方案了-谢谢:@user2439970当然可以,就这样!如果你只打算编译一个表达式,为什么还要传递它呢。如果您只需要一个委托,只需接受一个委托即可。@Servy true,但如果OP希望获取其他信息,如用于调试目的的属性名等,则表达式很有用。此时,您将返回到仅使用反射代码,而不是实际使用静态类型的系统。
groups =
(from item in objects
let propertyInfo = item.GetType().GetProperty(propertyName)
where propertyInfo != null
let propertyValue = (U)propertyInfo.GetValue(item, null)
group item by
groupsToMergeByProperty
.FirstOrDefault(ids => ids.Contains(propertyValue))
?.First()
?? propertyValue
into itemGroup
select itemGroup.ToArray())
.ToList();
public class Ext
{
public static List<T[]> MixObjectsByProperty<T, TProp, U>(
IEnumerable<T> source,
Expression<Func<T, TProp>> property,
IEnumerable<IEnumerable<U>> groupsToMix = null)
where T : class
where U : TProp
{
var prop = (PropertyInfo)(property.Body as MemberExpression)?.Member;
if (prop == null) throw new ArgumentException("Couldn't determine property");
var accessor = property.Compile();
var groups =
from item in source
let value = (U)accessor(item)
group item by
groupsToMix.FirstOrDefault((ids => ids.Contains(value)))
into itemGroup
select itemGroup.ToArray();
return groups.ToList();
}
}