摘要IEqualityComparer实现或覆盖默认比较器以使用Distinct方法

时间:2010-11-22 21:26:11

标签: c# generics distinct equals iequalitycomparer

我正在尝试找到一个不同的List<Author>给定一个List<BlogPost>,其中每个BlogPost都有一个Author属性。我在泛型中找到了Distinct()扩展方法,我正在尝试使用它。首先,让我解释一下我的循环以及我想要使用它的地方,然后我将解释我的课程以及我遇到麻烦的地方。

尝试在此处使用distinct

public List<Author> GetAuthors() {

  List<BlogPost> posts = GetBlogPosts();
  var authors = new List<Author>();

  foreach (var bp in posts) {
    authors.Add(bp.Author);
  }

  return authors.Distinct().ToList();
}

根据我read on MSDN的内容,Distinct()使用默认比较器或传入的比较器。我希望(我似乎不知道这是否可行)在一个地方编写一个比较器并且能够将它用于我的所有类,因为它们都通过完全相同的相等操作进行比较(比较{{1每个类的属性)。

我的所有类都继承自GUID类:

BasePage

我在public class BasePage : System.Web.UI.Page, IBaseTemplate, IEquatable<IBaseTemplate>, IEqualityComparer<IBaseTemplate> public class Author : BasePage public class BlogPost : BasePage 中实现的equals方法会比较每个属性唯一的BasePage属性。当我在GUID上致电Distinct()时,它似乎无效。有没有什么方法可以把比较器包装在一个地方并且始终能够使用它而不必编写类似Author的东西,因为我需要为每个类编写相同的东西,每次我想要使用class AuhorComparer : IEqualityComparer<Auhor>我可以以某种方式覆盖默认比较器,因此我不必将任何内容传递给Distinct()吗?

3 个答案:

答案 0 :(得分:2)

Distinct操作可能不是最好的解决方案,因为你最终只能构建一个带有重复项的潜在非常大的列表,然后立即将其缩小为不同的元素。最好从HashSet<Author>开始,以避免构建大型列表。

public List<Author> GetAuthors() { 
  HashSet<Author> authorSet = new HashSet<Author>();
  foreach (var author in GetBlogPosts().Select(x => x.Author)) {
    authorSet.Add(author);
  }
  return authorSet.ToList();
}

如果您确实想使用Distinct,那么最佳途径是在IEquatable类型上实施Author。如果未给出明确的IEqualityComparer Distinct,则其他LINQ方法最终将默认使用该类型的IEquatable实现。通常通过EqualityComprare<T>.Default

答案 1 :(得分:0)

覆盖等于应该适合你。可能出现问题的一件事是,GetHashCode不会与Equals一起被覆盖,而框架指南要求它应该发生。

答案 2 :(得分:0)

代码只显示了主要想法,我希望这将有用。

public class Repository
{
    public List<Author> GetAuthors()
    {
        var authors = new List<Author>
                        {
                            new Author{Name = "Author 1"},
                            new Author{Name = "Author 2"},
                            new Author{Name = "Author 1"}
                        };
        return authors.Distinct(new CustomComparer<Author>()).ToList();
    }

    public List<BlogPost> GetBlogPosts()
    {
        var blogPosts = new List<BlogPost>
        {
            new BlogPost {Text = "Text 1"},
            new BlogPost {Text = "Text 2"},
            new BlogPost {Text = "Text 1"}
        };
        return blogPosts.Distinct(new CustomComparer<BlogPost>()).ToList();
    }
}

//This comparer is required only one.
public class CustomComparer<T> : IEqualityComparer<T> where T : class
{
    public bool Equals(T x, T y)
    {
        if (y == null && x == null)
        {
            return true;
        }
        if (y == null || x == null)
        {
            return false;
        }
        if (x is Author && y is Author)
        {
            return ((Author)(object)x).Name == ((Author)(object)y).Name;
        }
        if (x is BlogPost && y is BlogPost)
        {
            return ((BlogPost)(object)x).Text == ((BlogPost)(object)y).Text;
        }
        //for next class add comparing logic here
        return false;
    }

    public int GetHashCode(T obj)
    {
        return 0; // actual generating hash code should be here
    }
}

public class Author
{
    public string Name { get; set; }
}

public class BlogPost
{
    public string Text { get; set; }
}