代码之家  ›  专栏  ›  技术社区  ›  Mark Ursino

抽象IEqualityComparer实现或重写默认比较器以使用Distinct方法

  •  0
  • Mark Ursino  · 技术社区  · 15 年前

    我想找出一个 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 , 非重复() 使用默认比较器或传入比较器。我希望(显然我不知道这是否可行)在一个位置编写一个比较器,并能够将其用于我的所有类,因为它们都通过完全相同的相等操作进行比较(该操作比较 GUID 每个类的属性)。

    我所有的课程都是从 BasePage 班级:

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

    我的equals方法在 基页 比较 指导方针 每个属性都是唯一的。当我打电话 非重复() 在一个 作者 好像没用。有没有什么方法可以把比较器包装在一个地方,并且总是能够使用它,而不必像 class AuhorComparer : IEqualityComparer<Auhor> 因为我需要为每门课写同样的东西,每次我想用 非重复() . 或者 我能不能以某种方式重写默认比较器,这样就不必向 独特() ?

    3 回复  |  直到 15 年前
        1
  •  2
  •   JaredPar    15 年前

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

    如果你真的想用 明显的 那么最好的办法就是 IEquatable Author 键入。当没有给出明确的 IEqualityComparer 这个 明显的 而其他LINQ方法最终将默认使用 不可量化 类型的实现。通常通过 EqualityComprare<T>.Default

        2
  •  0
  •   Igor Zevaka    15 年前

    重写等号应该对你有用。一个可能出错的地方是GetHashCode没有与Equals一起重写,框架指导原则规定应该这样做。

        3
  •  0
  •   Alexey    15 年前

    这段代码只显示了主要的思想,我希望它会有用。

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