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

发布于 2024-10-04 00:56:17 字数 1439 浏览 7 评论 0原文

我试图在给定 List 的情况下找到一个不同的 List,其中每个 BlogPost 都有一个 Author属性。我在泛型中找到了 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();
}

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

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

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

public class Author : BasePage

public class BlogPost : BasePage

BasePage 中实现的 equals 方法会比较每个唯一的 GUID 属性。当我在 Author 上调用 Distinct() 时,它似乎不起作用。有什么方法可以将比较器包装在一个地方并且始终能够使用它,而不必编写类似 class AuhorComparer : IEqualityComparer 的内容,因为我需要编写每次我想使用 Distinct() 时,每个类都会做同样的事情。 或者我可以以某种方式覆盖默认比较器,这样我就不必将任何内容传递给Distinct()吗?

I'm trying to find a distinct List<Author> given a List<BlogPost> where each BlogPost has an Author property. I've found the Distinct() extension method in generics and I'm trying to use it. 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. 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).

All of my classes inherit from the BasePage class:

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. When I call Distinct() on an Author it doesn't seem to work. 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(). Or can I override the default comparer somehow so I don't have to pass anything to Distinct()?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

调妓 2024-10-11 00:56:17

Distinct 操作可能不是这里的最佳解决方案,因为您最终会构建一个可能非常大的包含重复项的列表,然后立即将其缩小为不同的元素。最好从 HashSet 开始,以避免构建大型列表。

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,那么最好的途径是在 Author 类型上实现 IEquatable。如果没有给出显式的 IEqualityComparerDistinct 和其他 LINQ 方法最终将默认使用该类型的 IEquatable 实现。通常通过 EqualityComprare.Default

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. It's probably better to just start with a HashSet<Author> to avoid building up the large list.

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. When not given an explicit IEqualityComparer the Distinct and other LINQ methods will eventually default into using the IEquatable implementation on the type. Usually through EqualityComprare<T>.Default

Smile简单爱 2024-10-11 00:56:17

Overriden Equals 应该适合你。可能出现问题的一件事是 GetHashCode 没有与 Equals 一起被覆盖,而框架指南规定应该发生这种情况。

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.

沩ん囻菔务 2024-10-11 00:56:17

代码仅显示了主要思想,我希望这会有用。

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

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; }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文