2012-11-11 49 views
11

我在读一本关于Linq的书,看到Distinct方法有一个需要比较器的重载。这对于我想从集合中获取不同实体的问题是一个很好的解决方案,但即使其他属性不同,也希望将比较放在实体ID上。如何使用Linq Distinct方法使用自定义比较器?

按照书上的,如果我有一个Gribulator实体,我应该能够创建这样一个比较器...

private class GribulatorComparer : IComparer<Gribulator> { 
    public int Compare(Gribulator g1, Gribulator g2) { 
    return g1.ID.CompareTo(g2.ID); 
    } 
} 

...然后使用它像这样...

List<Gribulator> distinctGribulators 
    = myGribulators.Distinct(new GribulatorComparer()).ToList(); 

然而,这提供了以下编译器错误...

“System.Collections.Generic.List”不包含一个定义为“独特”和最佳推广方法重载“System.Linq.Enumerable .Distinct(System.Collections.Generic.IEnumerable,System.Collections.Generic.IEqualityComparer) '有一些无效参数

参数2:不能从转换 'LinqPlayground.Program.GribulatorComparer' 到' System.Collections.Generic.IEqualityComparer '

我已经搜索了一下,并且看到了很多使用这样的代码的例子,但没有抱怨编译器错误。

我在做什么错?另外,这是做这件事的最好方法吗?我想在这里提供一次性解决方案,所以不想开始更改实体本身的代码。我希望实体保持正常状态,但只在这一个地方,仅通过ID进行比较。

感谢您的任何帮助。

+0

忘了补充,我使用VS2012,因此.NET 4.0的C# –

回答

13

你实现你的比较器作为IComparer<T>,LINQ的方法重载需要IEqualityComparer实现:

private class GribulatorComparer : IEqualityComparer<Gribulator> { 
    public bool Equals(Gribulator g1, Gribulator g2) { 
    return g1.ID == g2.ID; 
    } 
} 

编辑:

为了澄清,IComparer接口可用于排序,如这基本上就是Compare()方法的作用。

像这样:

items.OrderBy(x => new ItemComparer()); 

private class ItemComparer : IComparer<Item> 
{ 
    public int Compare(Item x, Item y) 
    { 
     return x.Id.CompareTo(y.Id) 
    } 
} 

这将使用比较器进行排序您的收藏,但是LINQ提供了一种方法来做到这一点简单的字段(如一个int ID)。

items.OrderBy(x => x.Id); 
+0

感谢彼得,这就是了!我在本书中使用的例子是OrderBy,但他从他讨论的Distinct的位置提到了它,而且我还没有意识到我需要一个不同的界面。实际上并不是很清楚:( –

+0

顺便说一句,你知道是否有办法用匿名函数来做到这一点,而不必为比较器创建一个单独的类吗?看起来像过度杀伤 –

+0

到目前为止据我所知,没有,我实际上一直在考虑用这样的东西来重载linq运营商。 –