简体   繁体   English

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

[英]Abstract an IEqualityComparer implementation or override the default comparer to use Distinct method

I'm trying to find a distinct List<Author> given a List<BlogPost> where each BlogPost has an Author property. 我试图找到给定List<BlogPost>的不同List<Author> List<BlogPost> ,其中每个BlogPost都具有Author属性。 I've found the Distinct() extension method in generics and I'm trying to use it. 我在泛型中找到了Distinct()扩展方法,我正在尝试使用它。 First, let me explain my loop and where I want to use it, then I'll explain my classes and where I'm having trouble. 首先,让我解释一下我的循环以及在哪里使用它,然后再解释我的类以及在哪里遇到麻烦。

Trying to use distinct here 在这里尝试使用与众不同

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

Based on what I've read on MSDN , Distinct() either uses the default comparer or a passed in comparer. 根据我在MSDN阅读的内容Distinct()使用默认比较器或传入的比较器。 I was hoping (I obviosuly don't know if this is doable) to write a comparer in one spot and be able to use it for all of my classes since they all compare by the exact same equality operation (which compares the GUID property of each class). 我希望(我显然不知道这是否可行)在一个地方编写一个比较器,并能够将其用于我的所有类,因为它们都通过完全相同的相等操作(用于比较GUID属性)进行比较。每节课)。

All of my classes inherit from the BasePage class: 我的所有类都继承自BasePage类:

public class BasePage : System.Web.UI.Page, IBaseTemplate, IEquatable<IBaseTemplate>, IEqualityComparer<IBaseTemplate>

public class Author : BasePage

public class BlogPost : BasePage

My equals method implemented in BasePage compares the GUID property which is unique to each. 我在BasePage实现的equals方法比较了GUID属性,该属性对每个属性都是唯一的。 When I call Distinct() on an Author it doesn't seem to work. 当我在Author上调用Distinct()时,它似乎不起作用。 Is there any way I can wrap up the comparer in one place and always be able to use it rather than having to write something like class AuhorComparer : IEqualityComparer<Auhor> since I'd then need to write the same thing for each class, every time I want to use Distinct() . 有什么办法可以将比较器包装在一个地方,并且始终能够使用它,而不必编写class AuhorComparer : IEqualityComparer<Auhor>东西,因为那时我需要为每个类,每个类编写相同的东西时间我想使用Distinct() Or can I override the default comparer somehow so I don't have to pass anything to Distinct() ? 还是可以以某种方式覆盖默认比较器,这样我就不必将任何内容传递给Distinct()

The Distinct operation is probably not the best solution here because you end up building a potentially very big list with duplicates only to then immediately shrink it to distinct elements. Distinct操作可能不是这里的最佳解决方案,因为您最终构建了一个可能非常大的重复列表,然后立即将其缩小为不同的元素。 It's probably better to just start with a HashSet<Author> to avoid building up the large list. 最好从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();
}

If you do want to use Distinct then the best route is to implement IEquatable on the Author type. 如果您确实想使用Distinct那么最好的方法是在Author类型上实现IEquatable When not given an explicit IEqualityComparer the Distinct and other LINQ methods will eventually default into using the IEquatable implementation on the type. 当没有给出明确的IEqualityComparerDistinct和其他LINQ方法最终将默认使用类型上的IEquatable实现。 Usually through EqualityComprare<T>.Default 通常通过EqualityComprare<T>.Default

Overriden Equals should work for you. 覆盖等于应该为您工作。 One thing that might be going wrong is that GetHashCode is not overridden alongside Equals, which the framework guidelines dictate should happen. 可能出现问题的一件事是,GetHashCode不会与Equals一起被覆盖,而框架指南要求它应该发生。

The code only shows the main idea, which, I hope, will be useful. 代码只显示了主要的想法,我希望它会有用。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM