LINQ使用自定义IEqualityComparer进行Except操作

36
我正在尝试查找两个泛型列表之间的差异,就像下面的示例一样。 即使t1和t2包含相同的属性,它们也不是同一个对象,因此我需要实现一个IEqualityComparer。
这似乎可以使用此示例来实现,但是真正的类还有几个其他属性,我还需要对几个其他类执行相同的操作。
所以我想知道我是否在重新发明轮子?
是否有更简单的方法来比较两个对象的所有属性? 目前,我只需要处理包含简单类型的类,但如果有一个比较器可用于包含其他类实例的类,那将很好。
void Main()
{
    var t1 = new Sizes { Name = "Test" , Size = 1} ;
    var t2 = new Sizes { Name = "Test" , Size = 1} ;

    var list1 = new List<Sizes>();
    var list2 = new List<Sizes>();
    list1.Add(t1);
    list2.Add(t2);

    var differences = list2.Except(list1 , new SizesComparer());    
    // differences should be empty.
}


public class Sizes  
{
    public string Name { get;  set; }
    public int    Size { get;  set; }
}

public class SizesComparer : IEqualityComparer<Sizes>   
{
    bool IEqualityComparer<Sizes>.Equals(Sizes x, Sizes y)
    {            
        return (x.Name.Equals(y.Name) && x.Size.Equals(y.Size));        
    }

    int IEqualityComparer<Sizes>.GetHashCode(Sizes obj)
    {
        if (Object.ReferenceEquals(obj, null))
            return 0;               

        return obj.Name.GetHashCode() + obj.Size;       
    }
}

1
请参考IEnumerable.Except()和自定义比较器 - http://stackoverflow.com/q/1299513/485076 - sll
1
这个回答解决了你的问题吗?IEnumerable.Except()和自定义比较器 - Liam
2个回答

68

你可以尝试像这样做:

var differences = list2.Where(l2 => 
    !list1.Any(l1 => l1.Name == l2.Name && l1.Size == l2.Size));

或者如果你更喜欢:

var differences = list2.Where(l2 => 
    list1.All(l1 => l1.Name != l2.Name || l1.Size != l2.Size));

如果您将相同类型的对象添加到列表中,则此方法可以完美运行。 - Markus S
1
比起使用IEqualityComparer,这个更加简洁。谢谢。 - garyh

8
我最终使用的解决方案速度较慢,但这不是我的关注点。它能被重复使用,并且不受任何特定类的限制。该解决方案使用Newtonsoft.Json库将对象序列化为字符串,然后比较结果。这样做的优点是可以与匿名类和嵌套类一起使用。我假设比较方式首先调用两个对象的GetHashCode方法,如果它们匹配,则调用Equals方法,这意味着匹配的对象会被序列化两次。
public class JSonEqualityComparer<T> : IEqualityComparer<T>
{   
    public bool Equals(T x, T y)
    {           
        return String.Equals
        ( 
            Newtonsoft.Json.JsonConvert.SerializeObject(x), 
            Newtonsoft.Json.JsonConvert.SerializeObject(y)
        );                  
    }

    public int GetHashCode(T obj)
    {                           
        return Newtonsoft.Json.JsonConvert.SerializeObject(obj).GetHashCode();          
    }               
}       


public static partial class LinqExtensions
{
    public static IEnumerable<T> ExceptUsingJSonCompare<T>
        (this IEnumerable<T> first, IEnumerable<T> second)
    {   
        return first.Except(second, new JSonEqualityComparer<T>());
    }
}

为了使用它,您需要将 "Except" 替换为 "ExceptUsingJSonCompare",例如:
var differences = list2.ExceptUsingJSonCompare(list1); 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接