独特的不使用LINQ到对象

class Program { static void Main(string[] args) { List<Book> books = new List<Book> { new Book { Name="C# in Depth", Authors = new List<Author> { new Author { FirstName = "Jon", LastName="Skeet" }, new Author { FirstName = "Jon", LastName="Skeet" }, } }, new Book { Name="LINQ in Action", Authors = new List<Author> { new Author { FirstName = "Fabrice", LastName="Marguerie" }, new Author { FirstName = "Steve", LastName="Eichert" }, new Author { FirstName = "Jim", LastName="Wooley" }, } }, }; var temp = books.SelectMany(book => book.Authors).Distinct(); foreach (var author in temp) { Console.WriteLine(author.FirstName + " " + author.LastName); } Console.Read(); } } public class Book { public string Name { get; set; } public List<Author> Authors { get; set; } } public class Author { public string FirstName { get; set; } public string LastName { get; set; } public override bool Equals(object obj) { return true; //if (obj.GetType() != typeof(Author)) return false; //else return ((Author)obj).FirstName == this.FirstName && ((Author)obj).FirstName == this.LastName; } } 

这是基于“LINQ in Action”中的一个例子。 代码清单4.16

这打印了Jon Skeet两次。 为什么? 我甚至在Author类中尝试覆盖Equals方法。 仍然独特似乎不工作。 我错过了什么?

编辑:我也加了==和!=运算符超负荷。 仍然没有帮助。

  public static bool operator ==(Author a, Author b) { return true; } public static bool operator !=(Author a, Author b) { return false; } 

当谈到自定义对象时,LINQ Distinct并不是那么聪明。

它所做的就是查看你的列表,看看它有两个不同的对象(它并不在意它们的成员字段的值相同)。

一种解决方法是实现IEquatable接口,如下所示。

如果你修改你的作者类像这样应该工作。

 public class Author : IEquatable<Author> { public string FirstName { get; set; } public string LastName { get; set; } public bool Equals(Author other) { if (FirstName == other.FirstName && LastName == other.LastName) return true; return false; } public override int GetHashCode() { int hashFirstName = FirstName == null ? 0 : FirstName.GetHashCode(); int hashLastName = LastName == null ? 0 : LastName.GetHashCode(); return hashFirstName ^ hashLastName; } } 

Distinct()方法检查引用types的引用相等性。 这意味着它正在寻找字面上相同的对象重复,而不是不同的对象,其中包含相同的值。

有一个需要IEqualityComparer的重载 ,因此您可以指定不同的逻辑来确定给定对象是否等于另一个对象。

如果您希望作者通常performance得像一个普通的对象(即只有引用相等),但为了通过名称值区分检查相等的目的,请使用IEqualityComparer 。 如果您始终希望Author对象基于名称值进行比较,则覆盖GetHashCode和Equals ,或者实现IEquatable

IEqualityComparer接口上的两个成员是EqualsGetHashCode 。 如果第一个和最后一个名称string是相同的,则确定两个Author对象是否相等的逻辑似乎是。

 public class AuthorEquals : IEqualityComparer<Author> { public bool Equals(Author left, Author right) { if((object)left == null && (object)right == null) { return true; } if((object)left == null || (object)right == null) { return false; } return left.FirstName == right.FirstName && left.LastName == right.LastName; } public int GetHashCode(Author author) { return (author.FirstName + author.LastName).GetHashCode(); } } 

没有实现IEquatableEqualsGetHashCode另一个解决scheme是使用LINQs GroupBy方法,并从IGrouping中select第一个项目。

 var temp = books.SelectMany(book => book.Authors) .GroupBy (y => y.FirstName + y.LastName ) .Select (y => y.First ()); foreach (var author in temp){ Console.WriteLine(author.FirstName + " " + author.LastName); } 

Distinct()对枚举中的对象执行默认的相等比较。 如果你没有重写Equals()GetHashCode() ,那么它使用object的默认实现,它比较引用。

简单的解决scheme是将Equals()GetHashCode()正确实现添加到参与您正在比较的对象图(即Book和Author)的所有类中。

IEqualityComparer接口是一种方便的方法,当您无法访问需要比较的类的内部结构时,或者如果使用不同的比较方法,则允许您在单独的类中实现Equals()GetHashCode()

你已经覆盖了Equals(),但是确保你也覆盖了GetHashCode()

以上答案是错误的! 与MSDN上所述不同的是,返回默认的Equator,如前所述Default属性检查typesT是否实现System.IEquatable接口,如果是,则返回使用该实现的EqualityComparer。 否则,它返回一个EqualityComparer,它使用由T提供的Object.Equals和Object.GetHashCode的覆盖

这意味着只要你忽略了等于你没事。

你的代码不工作的原因是因为你检查名字==姓氏。

请参阅https://msdn.microsoft.com/library/bb348436(v=vs.100).aspx和https://msdn.microsoft.com/en-us/library/ms224763(v=vs.100).aspx

还有一种方法可以从用户定义的数据types列表中获取不同的值:

 YourList.GroupBy(i => i.Id).Select(i => i.First()).ToList(); 

当然,它会提供不同的数据