Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# c如何在通用IEnumerable上使用.Contains_C#_Linq_Generics_Ienumerable_Contains - Fatal编程技术网

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();
    }
}