繁体   English   中英

Enumerable.Except不使用我的自定义比较器

[英]Enumerable.Except does not use my custom comparer

我尝试使用自定义相等比较器的except方法,但它不起作用。

我的平等比较器:

public class BusinessObjectGuidEqualityComparer<T> : IEqualityComparer<T> where T : BusinessObject
{
    #region IEqualityComparer<T> Members

    /// <summary>
    /// Determines whether the specified objects are equal.
    /// </summary>
    /// <param name="x">The first object of type <paramref name="T"/> to compare.</param>
    /// <param name="y">The second object of type <paramref name="T"/> to compare.</param>
    /// <returns>
    /// <see langword="true"/> If the specified objects are equal; otherwise, <see langword="false"/>.
    /// </returns>
    public bool Equals(T x, T y)
    {
        return (x == null && y == null) || (x != null && y != null && x.Guid.Equals(y.Guid)); 
    }

    /// <summary>
    /// Returns a hash code for this instance.
    /// </summary>
    /// <param name="obj">The object to get the hash code.</param>
    /// <returns>
    /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. 
    /// </returns>
    /// <exception cref="T:System.ArgumentNullException">
    /// The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is null.
    /// </exception>
    public int GetHashCode(T obj)
    {
        if (obj == null)
        {
            throw new ArgumentNullException("obj");
        }

        return obj.GetHashCode();
    }

    #endregion
}

我的除了用法:

BusinessObjectGuidEqualityComparer<Area> comparer = new BusinessObjectGuidEqualityComparer<Area>();
IEnumerable<Area> toRemove = this.Areas.Except(allocatedAreas, comparer);
IEnumerable<Area> toAdd = allocatedAreas.Except(this.Areas, comparer);

奇怪的是,事件我提供我的自定义相等比较器使用默认值,所以我做错了什么?

感谢帮助。

类似于Marc,我刚测试了这个,一切都被称为正常,我的猜测是你被LINQ延迟执行捕获,注意我的代码中的ToArray。

请注意,在跟踪此操作时,我注意到比较器中的空对象永远不会调用GetHashCode。

请记住,MiscUtil有一个很棒的方式让你内联这些东西,请参阅: 我可以指定我的显式类型比较器内联吗?

或者你可以将它改编为Except: 基于LINQ中任意键的不同对象列表

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1 {

    public class BusinessObject {
        public Guid Guid { get; set; }
    }

    public class BusinessObjectGuidEqualityComparer<T> : IEqualityComparer<T> where T : BusinessObject {
        #region IEqualityComparer<T> Members

        public bool Equals(T x, T y) {
            return (x == null && y == null) || (x != null && y != null && x.Guid.Equals(y.Guid));
        }

        /// </exception>
        public int GetHashCode(T obj) {
            if (obj == null) {
                throw new ArgumentNullException("obj");
            }

            return obj.GetHashCode();
        }

        #endregion
    }

    class Program {
        static void Main(string[] args) {

            var comparer = new BusinessObjectGuidEqualityComparer<BusinessObject>();

            List<BusinessObject> list1 = new List<BusinessObject>() {
                new BusinessObject() {Guid = Guid.NewGuid()},
                new BusinessObject() {Guid = Guid.NewGuid()}
            };

            List<BusinessObject> list2 = new List<BusinessObject>() {
                new BusinessObject() {Guid = Guid.NewGuid()},
                new BusinessObject() {Guid = Guid.NewGuid()},
                null,
                null,
                list1[0]
            };

            var toRemove = list1.Except(list2, comparer).ToArray();
            var toAdd = list2.Except(list1, comparer).ToArray();

            // toRemove.Length == 1
            // toAdd.Length == 2
            Console.ReadKey();
        }
    }
}

尝试:

public int GetHashCode(T obj) {
    return obj == null ? 0 : obj.Guid.GetHashCode();
}

您的哈希码必须匹配相等(或者至少不与它相矛盾); 你的平等说“空位是平等的,否则比较指南”。 在内部,我希望Except使用HashSet<T> ,这解释了为什么让GetHashCode正确是如此重要


这是我的测试装备(使用上面的GetHashCode )工作正常:

public abstract class BusinessObject {
    public Guid Guid { get; set; }
}
class Area : BusinessObject {
    public string Name { get; set; }
    static void Main() {
        Guid guid = Guid.NewGuid();
        List<Area> areas = new List<Area> {
            new Area { Name = "a", Guid = Guid.NewGuid() },
            new Area { Name = "b", Guid = guid },
            new Area { Name = "c", Guid = Guid.NewGuid() },
        };
        List<Area> allocatedAreas = new List<Area> {
            new Area { Name = "b", Guid = guid},
            new Area { Name = "d", Guid = Guid.NewGuid()},
        };
        BusinessObjectGuidEqualityComparer<Area> comparer =
             new BusinessObjectGuidEqualityComparer<Area>();
        IEnumerable<Area> toRemove = areas.Except(allocatedAreas, comparer);
        foreach (var row in toRemove) {
            Console.WriteLine(row.Name); // shows a & c, since b is allocated
        }
    }
}

如果您的版本不起作用,您将不得不发布一些关于您如何使用它的内容,因为它对我来说很好(上图)。

您的相等比较器中的方法不匹配。 您正在比较对象的GUID,但GetHashCode方法使用基于引用的默认实现,而不是GUID。 由于不同的实例将获得不同的哈希码,尽管它们具有相同的GUID,但永远不会使用Equals方法。

GetHashCode方法中获取GUID的哈希码,因为这是您要比较的:

public int GetHashCode(T obj) {
    if (obj == null) {
        throw new ArgumentNullException("obj");
    }
    return obj.Guid.GetHashCode();
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM