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

C# 抽象IEqualityComparer实现或重写默认比较器以使用Distinct方法,c#,generics,distinct,equals,iequalitycomparer,C#,Generics,Distinct,Equals,Iequalitycomparer,我试图找到一个不同的列表给定一个列表,其中每个BlogPost都有一个作者属性。我在泛型中找到了Distinct()扩展方法,我正在尝试使用它。首先,让我解释我的循环以及我想在哪里使用它,然后我将解释我的类以及我遇到的问题 尝试在此处使用distinct public List<Author> GetAuthors() { List<BlogPost> posts = GetBlogPosts(); var authors = new List<Autho

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

BasePage
中实现的我的equals方法比较
GUID
属性,每个属性都是唯一的。当我对
作者调用
Distinct()
时,它似乎不起作用。有没有什么方法可以将比较器封装在一个地方并始终能够使用它,而不必编写类似于
class AuhorComparer:IEqualityComparer
的东西,因为每次我想使用
Distinct()
时,我都需要为每个类编写相同的东西我是否可以以某种方式重写默认比较器,这样我就不必将任何内容传递给
Distinct()

重写的Equals应该适用于您。可能出错的一件事是GetHashCode没有与Equals一起被重写,框架指导方针规定应该这样做

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();
}
public List GetAuthors(){
HashSet authorSet=新HashSet();
foreach(GetBlogPosts()中的var author.Select(x=>x.author)){
authorSet.Add(作者);
}
返回authorSet.ToList();
}

如果确实要使用
Distinct
,那么最好的方法是在
Author
类型上实现
IEquatable
。当没有给出显式的
IEqualityComparer
时,
Distinct
和其他LINQ方法最终将默认为在类型上使用
IEquatable
实现。通常通过
equalitycomplare.Default

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

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; }
}
公共类存储库
{
公共列表GetAuthors()
{
var authors=新列表
{
新作者{Name=“Author 1”},
新作者{Name=“Author 2”},
新作者{Name=“Author 1”}
};
返回authors.Distinct(new CustomComparer()).ToList();
}
公共列表GetBlogPosts()
{
var blogPosts=新列表
{
新建BlogPost{Text=“Text 1”},
新建BlogPost{Text=“Text 2”},
新建BlogPost{Text=“Text 1”}
};
返回blogPosts.Distinct(新的CustomComparer()).ToList();
}
}
//此比较器只需要一个。
公共类CustomComparer:IEqualityComparer其中T:class
{
公共布尔等于(TX,TY)
{
如果(y==null&&x==null)
{
返回true;
}
如果(y==null | | x==null)
{
返回false;
}
如果(x是作者&&y是作者)
{
返回((作者)(对象)x).Name==((作者)(对象)y).Name;
}
if(x是BlogPost&&y是BlogPost)
{
返回((BlogPost)(对象)x.Text==((BlogPost)(对象)y.Text;
}
//对于下一个类,请在此处添加比较逻辑
返回false;
}
公共int GetHashCode(T obj)
{
返回0;//实际生成的哈希代码应该在这里
}
}
公共类作者
{
公共字符串名称{get;set;}
}
公共类博客文章
{
公共字符串文本{get;set;}
}

感谢HashSet的建议。我实现了您的更改,但我仍然得到一个相同大小的列表。我列出了三篇文章,两篇是同一作者,一篇是完全不同的作者。不过,我得到了一个由3位作者组成的列表。HashSet多次包含同一位作者的事实是否证明我的Equals和GetHashCode方法写得不正确?我确认这不起作用,因为我的
GetHashCode
方法写得不正确。现在我有了
HashSet
工作的这种方法。谢谢
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; }
}