C# 获取不同列表的通用方法<;T>;

C# 获取不同列表的通用方法<;T>;,c#,generic-collections,C#,Generic Collections,我试图比较列表中类型的实例(属性值),并消除重复项。 根据MSDN,这是比较两个对象的方法之一 散列代码旨在有效地在中插入和查找 基于哈希表的集合。哈希代码不是一个 永久价值 考虑到这一点,我开始写我的扩展方法如下 public static class Linq { public static IEnumerable<T> DistinctObjects<T>(this IEnumerable<T> source) {

我试图比较列表中类型的实例(属性值),并消除重复项。 根据MSDN,这是比较两个对象的方法之一

散列代码旨在有效地在中插入和查找 基于哈希表的集合。哈希代码不是一个 永久价值

考虑到这一点,我开始写我的扩展方法如下

 public static class Linq 
    {
  public static IEnumerable<T> DistinctObjects<T>(this IEnumerable<T> source)
        {
            List<T> newList = new List<T>();
            foreach (var item in source)
            {
                if(newList.All(x => x.GetHashCode() != item.GetHashCode()))
                    newList.Add(item);
            }
            return newList;
        }
}
最后,我想用它像

MyDuplicateList.DistinctObjects().ToList();
如果比较对象的所有字段太多,我可以这样使用它

 MyDuplicateList.DistinctObjects(x=>x.Id, x.Name).ToList();

在这里,我要告诉你的是,只比较这些对象的这两个字段。

你不需要为此创建自己的自定义通用方法。相反,为您的数据类型提供自定义的
EqualityComparar

var myDuplicates = myList.Distinct(new MyComparer());
其中,您定义了如下自定义比较器:

public class MyComparer : IEqualityComparer<Mine>
{
    public bool Equals(Mine x, Mine y)
    {
        if (x == null && y == null) return true;            
        if (x == null || y == null) return false;
        return x.Name == y.Name && x.Id == y.Id;
    }

    public int GetHashCode(Mine obj)
    {
        return obj.Name.GetHashCode() ^ obj.Id.GetHashCode();
    }
}
公共类MyComparer:IEqualityComparer
{
公共布尔等于(我的x,我的y)
{
如果(x==null&&y==null)返回true;
如果(x==null | | y==null)返回false;
返回x.Name==y.Name&&x.Id==y.Id;
}
公共int GetHashCode(矿山obj)
{
返回obj.Name.GetHashCode()^obj.Id.GetHashCode();
}
}

编辑:我最初在这里的代码不正确,这应该可以满足您的需要,而不必重写
Equals
运算符

在阅读您的评论后,我将提出以下解决方案:

   public static IEnumerable<TSource> DistinctBy<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
    {
        HashSet<TResult> set = new HashSet<TResult>();

        foreach(var item in source)
        {
            var selectedValue = selector(item);

            if (set.Add(selectedValue))
                yield return item;
        }
    }
或者对于类似的多个属性:

var distinctedList = myList.DistinctBy(x => new {x.A,x.B});

此解决方案的优点是,您可以准确地指定应在区分中使用哪些属性,并且不必为每个对象重写
Equals
GetHashCode
。您需要确保可以比较您的属性。

有一个内置的LINQ函数,
Distinct()
,它使用一个表达式来确定唯一性。这不是你想要的吗?首先,如果GetHashCode是相等的,并不意味着对象是相等的,而是相反的round@GEEF.Distinct()没有执行此任务。@YacoubMassad GetHashCode()肯定是由T实现的,考虑到它基于C#
对象
。它不做这项工作,因为您需要使用比较器或实现接口IEquatable for object,重写equals和gethashcode,否则它会比较引用如果要显示equals/gethashcode实现,至少要确保正确执行,Equals可能会在出现null异常时崩溃,并且您忘记了GetHashCode中的素数。正确执行此函数不需要素数。但肯定会因为NRE而崩溃,不过他可以填写一些细节。等一下,这是否只返回我传入的Distinct(x=>x.Id)对象?@HaBo否,返回类型是IEnumerable。请在MSDN上阅读。这是一个很好的方法!最好的方法仍然是在每个对象中实现一个适当的equals/gethashcode,因为默认情况下,如果没有这些,您可能会遇到很多问题
var distinctedList = myList.DistinctBy(x => x.A);
var distinctedList = myList.DistinctBy(x => new {x.A,x.B});