c# 如何在通用 IEnumerable<T> 上使用 .Contains
c# How To Use .Contains on Generic IEnumerable<T>
我正在尝试创建一个通用方法,我想用它来混合基于 属性 的对象列表。或者,您可以提供列表对象列表以将一些组合并在一起。这作为一种非通用方法工作得很好,当我手动编码 属性 等
方法头:
public static IEnumerable<T> MixObjectsByProperty<T>(
IEnumerable<T> objects,
string propertyName,
IEnumerable<IEnumerable<T>> groupsToMergeByProperty = null)
方法正文片段:
groups =
(from item in objects
let propertyInfo = item.GetType().GetProperty(propertyName)
where propertyInfo != null
group item by groupsToMergeByProperty
.FirstOrDefault(ids => ids.Contains(propertyInfo.GetValue(item, null)))
//.FirstOrDefault(ids => ids.Any(propertyInfo.GetValue(item, null)))
?.First()
?? propertyInfo.GetValue(item, null)
into itemGroup
select itemGroup.ToArray())
.ToList();
如您所见,我在 IEnumerable<T>
上使用 contains 方法时遇到问题,因为 propertyInfo.GetValue(item, null)
正在返回一个对象。我尝试了各种铸造尝试并使用 .Any()
代替,但我遇到了障碍:(
任何帮助都会很棒,谢谢!
此外,如果您需要更多信息,请告诉我,但我想,从本质上讲,我需要知道的是如何使用 .Contains()
使用 <T>
。
将它们设置为同一类型?自定义 IEqualityComparer
?
I've tried various casting attempts
你试过这个吗?
.FirstOrDefault(ids => ids.Contains((T)propertyInfo.GetValue(item, null)))
由于 ids
是 IGrouping<TKey, TElement>
类型,其中 TElement
是 T
类型,因此将 属性 的值转换为 T
将允许进行比较。
好的,所以我最终还是破解了。我需要在我的通用方法 header/signature.
中添加更多细节
public static IEnumerable<T> MixObjectsByProperty<T, U>(
IEnumerable<T> objects, string propertyName, IEnumerable<IEnumerable<U>> groupsToMergeByProperty = null)
where T : class
where U : class
{
...
注意,我添加了 class 约束,允许我使用可空运算符等。
正文变成了(在添加了一个转换为正确类型的 propertyValue 变量之后!):
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();
}
}
看在上帝的份上 停止传递 属性 名称并使用反射,Linq 的其余部分使用华丽的表达系统,您也应该这样做!
我正在尝试创建一个通用方法,我想用它来混合基于 属性 的对象列表。或者,您可以提供列表对象列表以将一些组合并在一起。这作为一种非通用方法工作得很好,当我手动编码 属性 等
方法头:
public static IEnumerable<T> MixObjectsByProperty<T>(
IEnumerable<T> objects,
string propertyName,
IEnumerable<IEnumerable<T>> groupsToMergeByProperty = null)
方法正文片段:
groups =
(from item in objects
let propertyInfo = item.GetType().GetProperty(propertyName)
where propertyInfo != null
group item by groupsToMergeByProperty
.FirstOrDefault(ids => ids.Contains(propertyInfo.GetValue(item, null)))
//.FirstOrDefault(ids => ids.Any(propertyInfo.GetValue(item, null)))
?.First()
?? propertyInfo.GetValue(item, null)
into itemGroup
select itemGroup.ToArray())
.ToList();
如您所见,我在 IEnumerable<T>
上使用 contains 方法时遇到问题,因为 propertyInfo.GetValue(item, null)
正在返回一个对象。我尝试了各种铸造尝试并使用 .Any()
代替,但我遇到了障碍:(
任何帮助都会很棒,谢谢!
此外,如果您需要更多信息,请告诉我,但我想,从本质上讲,我需要知道的是如何使用 .Contains()
使用 <T>
。
将它们设置为同一类型?自定义 IEqualityComparer
?
I've tried various casting attempts
你试过这个吗?
.FirstOrDefault(ids => ids.Contains((T)propertyInfo.GetValue(item, null)))
由于 ids
是 IGrouping<TKey, TElement>
类型,其中 TElement
是 T
类型,因此将 属性 的值转换为 T
将允许进行比较。
好的,所以我最终还是破解了。我需要在我的通用方法 header/signature.
中添加更多细节 public static IEnumerable<T> MixObjectsByProperty<T, U>(
IEnumerable<T> objects, string propertyName, IEnumerable<IEnumerable<U>> groupsToMergeByProperty = null)
where T : class
where U : class
{
...
注意,我添加了 class 约束,允许我使用可空运算符等。
正文变成了(在添加了一个转换为正确类型的 propertyValue 变量之后!):
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();
}
}
看在上帝的份上 停止传递 属性 名称并使用反射,Linq 的其余部分使用华丽的表达系统,您也应该这样做!