• 【.net 深呼吸】EqualityComparer——自定义相等比较


    自定义实现两个对象的相等比较,一种方案是重写Object类的Equals方法,很easy,如果相等返回true,不相等就返回false。不过,如果把自定义相等的比较用于泛型集,比如Dictionary、HashSet等,这些集合都有一个共同点——必须标识存储项的唯一性,即每一个子项都有对应的key。

    object.Equals方法是面向Object类型的,如果用于泛型对象,在判断是否相等的过程需要进行大量的装箱/拆箱操作,尤其是复合类型,由于要进行细致的比较,类型转换更为频繁,这样会带来一定量的性能开销,所以,对于泛型集合的相等比较,应该考虑使用 IEqualityComparer<T>,Dotnet类型提供了一个实现了该接口的抽象类——EqualityComparer<T>。

    在实际使用中,不妨直接实现这个抽象类,好处是该抽象类公开了一个静态的Default属性,可以返回平台默认的比较方案。因此,实现该抽象类的好处在于,既可以提供自定义实现,同时也可以保留默认行为。

    我们先来解释一下,为什么在泛型集合中需要用到自定义相等比较。看例子,咱们以常用的Dictionary为例,字典的Key我用一个叫Entity的类来标识,该类定义如下。

        public class Entity
        {
            public int ID { get; set; }
            public string Name { get; set; }
        }

    然后,我们实例化一个字典,并向其中添加两个项。

                IDictionary<Entity, string> dic = new Dictionary<Entity, string>();
    
                dic.Add(new Entity { ID = 1, Name = "小明" }, "C++");
                dic.Add(new Entity { ID = 2, Name = "小王" }, "VB");

    接着,从字典中读出Key为ID = 2 , Name = "小王" 的值。

                Entity findkey = new Entity
                {
                    ID = 2,
                    Name = "小王"
                };
    
                if (dic.ContainsKey(findkey))
                {
                    Console.WriteLine(dic[findkey]);
                }

    在查找时,先实例化一个Entity,然后给ID和Name属性赋上要查找的值,随后调用字典实例的ContainsKey方法判断一下要查找的key是否存在于字典中,如果存在,就输出该key对应的值。

    代码看起来很完美,但一旦运行,你会发现什么都没找到。为啥呢?

    因为该字典存储项的key是我们自定义的Entity类,当我们要从中查找时,是另外实例化了一个Entity对象,并赋了对应的属性值去查找的,可是问题就来了,我们实例化的findkey对象,与存入到字典中的Entity不是同一个对象,虽然它们的属性值相等,但它们引用的不是同一个实例,因为被判定为不相等的对象,故找不到对应的Key。

    这个时候,EqualityComparer就派上用场了,自定义一个类并从它派生,添加自己的代码实现,不管是不是同一个对象实例,只要属性的值相等,则视为相同的key。

        public sealed class CustomEqComparer : EqualityComparer<Entity>
        {
            public override bool Equals(Entity x, Entity y)
            {
                if (x.ID == y.ID && x.Name == y.Name)
                    return true;
                return false;
            }
    
            public override int GetHashCode(Entity obj)
            {
                return obj.ID.GetHashCode();
            }
        }

    实现Equals方法,如果两个对象相等,返回真,否则返回假。GetHashCode方法返回哈希值,算法不应该过于复杂,避免性能开销,只要能够保证相等的两个对象返回相同的哈希值;不相等的对象返回不同的哈希值,这样就可以了。这里直接以ID属性的值为哈希,所以,每个key的ID值不能重复。

    自定义完比较器后,只要在实例化字典实例时传给它的构造函数就可以了。把上面的代码改为:

                CustomEqComparer comp = new CustomEqComparer();
                IDictionary<Entity, string> dic = new Dictionary<Entity, string>(comp);

    现在,再次执行前面的例子,ID=2,Name="小王"的key就可以查找出来了。

    完整的演示代码如下:

        class Program
        {
            static void Main(string[] args)
            {
                CustomEqComparer comp = new CustomEqComparer();
                IDictionary<Entity, string> dic = new Dictionary<Entity, string>(comp);
    
                dic.Add(new Entity { ID = 1, Name = "小明" }, "C++");
                dic.Add(new Entity { ID = 2, Name = "小王" }, "VB");
    
                Entity findkey = new Entity
                {
                    ID = 2,
                    Name = "小王"
                };
    
                if (dic.ContainsKey(findkey))
                {
                    Console.WriteLine(dic[findkey]);
                }
    
    
                Console.Read();
            }
        }
    
        public class Entity
        {
            public int ID { get; set; }
            public string Name { get; set; }
        }
    
        public sealed class CustomEqComparer : EqualityComparer<Entity>
        {
            public override bool Equals(Entity x, Entity y)
            {
                if (x.ID == y.ID && x.Name == y.Name)
                    return true;
                return false;
            }
    
            public override int GetHashCode(Entity obj)
            {
                return obj.ID.GetHashCode();
            }
        }
  • 相关阅读:
    iOS 字符串的UTF8 编码 以及归档反归档
    iOS 关于关键字高亮
    iOS 适配 ,关于prefix Header 文件的配置
    关于collectionView 的头视图
    关于页面的下拉刷新,和上拉加载 --- > collectionView ,tableView
    Nums数独计算器的感谢版,有3种解题方式,过去注册的也是可以用
    Nums数独计算器,良心软件,给不给钱都是可以的
    人生不过是给自己找一些痕迹,证明自己存在过
    做些有益的事情,人生要懂得自重
    振作才是自己可以走的路,人生不要放弃自己的争取
  • 原文地址:https://www.cnblogs.com/tcjiaan/p/5700192.html
Copyright © 2020-2023  润新知