开发者

Linq Except with custom IEqualityComparer

I am trying to find the difference between two generic lists, as in the example below. Even though t1 and t2 contain the same properties, they are not the same object, so I have need to implement an IEqualityComparer.

This appears to be working with this example, but the real class has several other properties and I also need to do the same with a few other class.

So I was wondering if I am re-inventing the wheel?

Is there an easier method of comparing all the properties of two objects? At t开发者_Python百科he moment, I really only need to cope with class containing simple types, but it would be nice I have a comparer that worked with classes that contains instances of other classes.

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


You could try something like:

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

Or if you prefer:

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


The solution which I ended up using could not be described as fast, but that is not a concern of mine and it does what I want in that it can be re-used and is not restricted to any particular class.

It uses the Newtonsoft.Json library to serialize the object to a string and then compares the result. This also has the advantage of working with anonymous classes and nested classes.

I am assuming that the way the comparison works is that it first calls GetHashCode on both objects and if they match it then calls Equals, which in this routine will mean that matching objects will be serialized twice.

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

To use it you swap Except with ExceptUsingJSonCompare, for example :

var differences = list2.ExceptUsingJSonCompare(list1); 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜