Linq except 使用自定义 IEqualityComparer

发布于 2024-11-29 13:19:55 字数 1181 浏览 1 评论 0原文

我试图找出两个通用列表之间的差异,如下例所示。 尽管 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;       
    }
}

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

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

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

发布评论

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

评论(2

⒈起吃苦の倖褔 2024-12-06 13:19:55

您可以尝试以下操作:

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

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));
萌无敌 2024-12-06 13:19:55

我最终使用的解决方案不能被描述为快速,但这不是我关心的问题,它满足我的要求,因为它可以重复使用并且不限于任何特定的类。

它使用 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); 

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