tnblog
首页
视频
资源
登录

EqualityComparer自定义相等比较

5293人阅读 2021/4/19 15:47 总访问:3467163 评论:0 收藏:0 手机
分类: .net后台框架

.netcore

EqualityComparer自定义相等比较


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

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

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

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

  1. public class Entity
  2. {
  3. public int ID { get; set; }
  4. public string Name { get; set; }
  5. }

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

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

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

  1. Entity findkey = new Entity
  2. {
  3. ID = 2,
  4. Name = "小王"
  5. };
  6. if (dic.ContainsKey(findkey))
  7. {
  8. Console.WriteLine(dic[findkey]);
  9. }


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

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

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

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

  1. public sealed class CustomEqComparer : EqualityComparer<Entity>
  2. {
  3. public override bool Equals(Entity x, Entity y)
  4. {
  5. if (x.ID == y.ID && x.Name == y.Name)
  6. return true;
  7. return false;
  8. }
  9. public override int GetHashCode(Entity obj)
  10. {
  11. return obj.ID.GetHashCode();
  12. }
  13. }


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

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

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


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

完整的演示代码如下:

  1. class Program
  2. {
  3. static void Main(string[] args)
  4. {
  5. CustomEqComparer comp = new CustomEqComparer();
  6. IDictionary<Entity, string> dic = new Dictionary<Entity, string>(comp);
  7. dic.Add(new Entity { ID = 1, Name = "小明" }, "C++");
  8. dic.Add(new Entity { ID = 2, Name = "小王" }, "VB");
  9. Entity findkey = new Entity
  10. {
  11. ID = 2,
  12. Name = "小王"
  13. };
  14. if (dic.ContainsKey(findkey))
  15. {
  16. Console.WriteLine(dic[findkey]);
  17. }
  18. Console.Read();
  19. }
  20. }
  21. public class Entity
  22. {
  23. public int ID { get; set; }
  24. public string Name { get; set; }
  25. }
  26. public sealed class CustomEqComparer : EqualityComparer<Entity>
  27. {
  28. public override bool Equals(Entity x, Entity y)
  29. {
  30. if (x.ID == y.ID && x.Name == y.Name)
  31. return true;
  32. return false;
  33. }
  34. public override int GetHashCode(Entity obj)
  35. {
  36. return obj.ID.GetHashCode();
  37. }
  38. }

欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

评价
这一世以无限游戏为使命!
排名
2
文章
634
粉丝
44
评论
93
docker中Sware集群与service
尘叶心繁 : 想学呀!我教你呀
一个bug让程序员走上法庭 索赔金额达400亿日元
叼着奶瓶逛酒吧 : 所以说做程序员也要懂点法律知识
.net core 塑形资源
剑轩 : 收藏收藏
映射AutoMapper
剑轩 : 好是好,这个对效率影响大不大哇,效率高不高
ASP.NET Core 服务注册生命周期
剑轩 : http://www.tnblog.net/aojiancc2/article/details/167
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术