c#如何使用.Contains on Generic IEnumerable <t>

时间:2017-06-19 10:43:11

标签: c# linq generics ienumerable contains

我试图创建一个泛型方法,我想用它来混合一个属性的对象列表。 (可选)您可以提供列表对象列表以将某些组合并在一起。这可以作为非泛型方法正常工作,当我手动编写属性等时

方法主管:

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

将它们设置为相同的类型?自定义$('.my-input:checked').each(function() { //do something });

3 个答案:

答案 0 :(得分:1)

  

我尝试了各种投射尝试

你试过这个吗?

.FirstOrDefault(ids => ids.Contains((T)propertyInfo.GetValue(item, null)))

由于ids的类型为IGrouping<TKey, TElement>,其中TElement的类型为T,因此将属性值强制转换为T将允许比较。

答案 1 :(得分:1)

没有看到整个方法(因为你的类型签名清楚地表明它不是整个方法),这里是一个示例实现:

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的其余部分使用华丽的表达系统,你也应该这样做!

答案 2 :(得分:-1)

好的,所以我最终破解了它。我需要在我的通用方法标题/签名中添加更多细节。

    public static IEnumerable<T> MixObjectsByProperty<T, U>(
        IEnumerable<T> objects, string propertyName, IEnumerable<IEnumerable<U>> groupsToMergeByProperty = null)
        where T : class
        where U : 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();