C# 实现一个基于值相等性比较的字典

C# 实现一个基于值相等性比较的字典

Intro

今天在项目里遇到一个需求,大概是这样的我要比较两个 JSON 字符串是不是相等,JSON 字符串其实是一个 Dictionary<string, string> 但是顺序可能不同,和上一篇 record 使用场景中的第一个需求类似,前面我们介绍过使用 record 可以比较方便的解决,但是我们的项目是 .netcoreapp3.1 的,不能使用 record,如何比较方便的比较呢?我们能否自己实现一个类似于 record 的类型,基于值去比较呢?于是就有了本文的探索

StringValueDictioanry

实现了一个基于值进行比较的字典,实现代码如下,实现的比较简单,涉及到一些简单的知识点,平时不怎么用已经忘了怎么写了,通过写下面的代码又学习了一下

先来看测试代码吧,测试代码如下:

[Fact]
public void EqualsTest()
{var abc = new { Id = 1, Name = "Tom" };var dic1 = StringValueDictionary.FromObject(abc);var dic2 = StringValueDictionary.FromObject(new Dictionary<string, object>(){{"Name", "Tom" },{"Id", 1},});Assert.True(dic1 == dic2);Assert.Equal(dic1, dic2);
}[Fact]
public void DistinctTest()
{var abc = new { Id = 1, Name = "Tom" };var dic1 = StringValueDictionary.FromObject(abc);var dic2 = StringValueDictionary.FromObject(new Dictionary<string, object>(){{"Id", 1},{"Name", "Tom" },});var set = new HashSet<StringValueDictionary>();set.Add(dic1);set.Add(dic2);Assert.Single(set);
}[Fact]
public void CloneTest()
{var dic1 = StringValueDictionary.FromObject(new Dictionary<string, object>(){{"Id", 1},{"Name", "Tom" }});var dic2 = dic1.Clone();Assert.False(ReferenceEquals(dic1, dic2));Assert.True(dic1 == dic2);
}[Fact]
public void ImplicitConvertTest()
{var abc = new { Id = 1, Name = "Tom" };var stringValueDictionary = StringValueDictionary.FromObject(abc);Dictionary<string, string> dictionary = stringValueDictionary;Assert.Equal(stringValueDictionary.Count, dictionary.Count);var dic2 = StringValueDictionary.FromObject(dictionary);Assert.Equal(dic2, stringValueDictionary);Assert.True(dic2 == stringValueDictionary);
}

从上面的代码可能大概能看出一些实现,重写了默认的 EqualsGetHashCode,并重载了“==” 运算符,并且实现了一个从 StringValueDictionaryDictionary 的隐式转换,来看下面的实现代码:

public sealed class StringValueDictionary : IEquatable<StringValueDictionary>
{private readonly Dictionary<string, string?> _dictionary = new();private StringValueDictionary(IDictionary<string, string?> dictionary){foreach (var pair in dictionary){_dictionary[pair.Key] = pair.Value;}}private StringValueDictionary(StringValueDictionary dictionary){foreach (var key in dictionary.Keys){_dictionary[key] = dictionary[key];}}public static StringValueDictionary FromObject(object obj){if (obj is null) throw new ArgumentNullException(nameof(obj));if (obj is IDictionary<string, string?> dictionary){return new StringValueDictionary(dictionary);}if (obj is IDictionary<string, object?> dictionary2){return new StringValueDictionary(dictionary2.ToDictionary(p => p.Key, p => p.Value?.ToString()));}if (obj is StringValueDictionary dictionary3){return new StringValueDictionary(dictionary3);}return new StringValueDictionary(obj.GetType().GetProperties().ToDictionary(p => p.Name, p => p.GetValue(obj)?.ToString()));}public static StringValueDictionary FromJson(string json){Guard.NotNull(json, nameof(json));var dic = json.JsonToObject<Dictionary<string, object?>>().ToDictionary(x => x.Key, x => x.Value?.ToString());return new StringValueDictionary(dic);}public StringValueDictionary Clone() => new(this);public int Count => _dictionary.Count;public bool ContainsKey(string key) => _dictionary.ContainsKey(key) ? _dictionary.ContainsKey(key) : throw new ArgumentOutOfRangeException(nameof(key));public string? this[string key] => _dictionary[key];public Dictionary<string, string>.KeyCollection Keys => _dictionary.Keys!;public bool Equals(StringValueDictionary? other){if (other is null) return false;if (other.Count != Count) return false;foreach (var key in _dictionary.Keys){if (!other.ContainsKey(key)){return false;}if (_dictionary[key] != other[key]){return false;}}return true;}public override bool Equals(object obj){return Equals(obj as StringValueDictionary);}public override int GetHashCode(){var stringBuilder = new StringBuilder();foreach (var pair in _dictionary){stringBuilder.Append($"{pair.Key}={pair.Value}_");}return stringBuilder.ToString().GetHashCode();}public static bool operator ==(StringValueDictionary? current, StringValueDictionary? other){return current?.Equals(other) == true;}public static bool operator !=(StringValueDictionary? current, StringValueDictionary? other){return current?.Equals(other) != true;}public static implicit operator Dictionary<string, string?>(StringValueDictionary dictionary){return dictionary._dictionary;}
}

More

上述代码实现的有点粗糙,可能会有一些问题,仅供参考

以上代码基本实现了基于想要的值的相等性比较以及 Clone(复制、克隆)的目标

实现相等性比较的时候,EqualsGetHashCode 方法也要重写,如果没有重写 GetHashCode,编译器也会给出警告,如果没有重写 GetHashCode 在实际在 HashSet 或者 Dictionary 里可能会出现重复 key

重载运算符的时候需要一个静态方法,"==" 和 "!=" 是一对操作运算符,如果要实现两个都要实现,不能只实现其中一个

implicit  也算是一个特殊的运算符,巧妙的使用隐式转换可以大大简化代码的写法,StackExchange.Redis 中就使用了 implicit 来实现 RedisValue 和 string 等其他常用类型的隐式转换

References

  • https://github.com/WeihanLi/WeihanLi.Common/blob/dev/src/WeihanLi.Common/Models/StringValueDictionary.cs

  • https://github.com/WeihanLi/WeihanLi.Common/blob/dev/test/WeihanLi.Common.Test/ModelsTest/StringValueDictionaryTest.cs

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/305318.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RIAMeeting第六次开发者交流活动。

5月的一场大地震带给我们过多的悲痛&#xff0c;但国家还要兴起&#xff0c;技术还要进步&#xff0c;让广大RIA开发者化悲愤为力量&#xff0c;继续开创中国的RIA事业吧&#xff01; 本月的25日&#xff0c;RIAMeeting将举办第六次开发者交流活动&#xff0c;本次活动邀请到了…

java字符串转时间_java字符串和时间转换

import java.text.SimpleDateFormat; import java.util.Date; //将long字符串转换成格式时间输出 public class LongToString {public static void main(String argsp[]){String time="1256006105375"; Date date=new Date(Long.parseLong(time)); SimpleDateFormat …

java 堆栈_Java中线程与堆栈的关系

栈是线程私有的&#xff0c;每个线程都是自己的栈&#xff0c;每个线程中的每个方法在执行的同时会创建一个栈帧用于存局部变量表、操作数栈、动态链接、方法返回地址等信息。每一个方法从调用到执行完毕的过程&#xff0c;就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。其…

巧用lock解决缓存击穿的解决方案

背景缓存击穿是指缓存中没有但数据库中有的数据&#xff08;一般是缓存时间到期&#xff09;&#xff0c;这时由于并发用户特别多&#xff0c;同时读缓存没读到数据&#xff0c;又同时去数据库去取数据&#xff0c;引起数据库压力瞬间增大&#xff0c;造成过大压力。解决方案1、…

ISA禁止了symantec的LiveUpdate的使用

从我们服务器将symantec升级到10.1.5.5000后&#xff0c;就发现ISA客户端的用户&#xff0c;用LiveUpdate没法升级&#xff0c;点击按钮后也会运行升级&#xff0c;但是到最后总是出现一个红色的大叉&#xff0c;说升级失败。这样客户端就只剩下手动用升级包升级或者是通过服务…

java怎么将前端的数据存到关联的表中_Java程序员最可能被考到的14个面试题

1. 如何只扫描一遍就找到位于一个链表正中间的元素&#xff1f; 这是最受欢迎的算法题之一&#xff0c;经常在电话面试中被问到。很多程序员会想&#xff0c;要知道链表的长度&#xff0c;就要先扫描一遍链表&#xff0c;然后在第二遍中取其正中的元素。所以被要求只扫描一遍就…

java 监听文件内容_java 监听文件内容变化

有时候&#xff0c;我们需要确定某些文件是否有变化而做出一些对应的动作&#xff0c;例如&#xff0c;曾经开发的一款服务器中&#xff0c;由于模块比较多&#xff0c;在运行期间有时候需要单独的输出某个模块日志&#xff0c;但又不可能总是开着日志。log4j中已经实现了可以动…

.NET Core 和 .NET Framework 启动可执行文件的差别

在 Windows 下&#xff0c;使用 .NET Framework 构建出来的应用&#xff0c;可以只有一个可执行文件&#xff0c;在可执行文件里面包含了 IL 代码。使用 .NET Core 构建出来的应用&#xff0c;将会包含一个 Exe 可执行文件&#xff0c;和对应的 Dll 文件&#xff0c;而 IL 代码…

firefox 3.0 在 windows 下的编译

&#xff08;1&#xff09;下载firefox 3.0源代码。下载并安装 mozilla-build &#xff08;2&#xff09;运行 start-msvc9.bat&#xff0c;进入shell界面&#xff0c; 查看环境变量&#xff1a; echo $PATH echo $LIB echo $INCLUDE &#xff08;3&#xff09;确保: windo…

常见的几种最优化方法

阅读目录1. 梯度下降法&#xff08;Gradient Descent&#xff09;2. 牛顿法和拟牛顿法&#xff08;Newtons method & Quasi-Newton Methods&#xff09;3. 共轭梯度法&#xff08;Conjugate Gradient&#xff09;4. 启发式优化方法我们每个人都会在我们的生活或者工作中遇到…

安卓平板运行python_使用Python进行手机平板移动开发 | 学步园

过去&#xff0c;Android和iOS上的移动应用程序开发不是Python的强项&#xff0c;但情况可能会发生变化……使用Python进行移动应用开发怎么样&#xff1f;从历史上看&#xff0c;在编写移动GUI应用程序时&#xff0c;Python并没有很强的故事。实际上&#xff0c;仅使用纯Pytho…

专业的软件安装包可以这样做!

C/S客户端开发完成&#xff0c;需要将程序交付给用户&#xff0c;直接压缩发给用户是可以的&#xff08;只是有点不专业&#xff09;&#xff0c;如果能有一个比较好看的安装界面&#xff0c;那档次就不一样了。本文介绍怎么使用Adanced Installer 17.9 制作专业的Windows 客户…

jsp需要多少java基础_Java基础——JSP(一)

注意&#xff1a;访问JSP的过程如果是第一次访问服务器&#xff0c;则翻译成一个对应的java文件(Servlet)。然后&#xff0c;再被编成 .class 文件并加载到内存中。如果是以后访问&#xff0c;则直接调用内存中的jsp实例&#xff0c;所以第一次访问慢,以后访问会更加快。四、3种…

宝贝,对不起

宝贝&#xff0c;对不起 题记:读在地震中用生命保护三个月大的婴儿的伟大母亲的遗言 “亲爱的宝贝&#xff0c;如果你能活着&#xff0c;请一定要记得我爱你”有感 谨以此文献给那逝去的伟大母亲和幸存下来坚强的宝贝 ——代腾飞 2008年5月21日 于成都 面对这突如其来的空前灾…

IT人喝酒,不同岗位不同姿势

这是Boss们的常用套路&#xff0c;频频举杯&#xff0c;给大家鼓劲加油&#xff0c;但是自己不喝。有的销售&#xff0c;业绩好&#xff0c;酒品也好&#xff0c;不管和自己人喝酒&#xff0c;还是和客户喝酒&#xff0c;都是一副舍我其谁的霸气&#xff01;这是某些销售的写照…

国产CPU群雄逐鹿谁主沉浮

当下&#xff0c;国内&#xff08;桌面、服务器&#xff09;CPU与外商有较大差距&#xff0c;除了海光在性能上可能具有一拼之力外&#xff0c;其它国产CPU在商业市场上面对英特尔、AMD基本不具备竞争力&#xff0c;因而只能在篱笆墙内的市场角逐。而为了能够进入篱笆墙内的市场…

让网站性能最佳的34条黄金守则

Yahoo!的Exceptional Performance团队为改善Web性能带来最佳实践。他们为此进行了一系列的实验、开发了各种工具、写了大量的文章和博客并在各种会议上参与探讨。最佳实践的核心就是旨在提高网站性能。Excetional Performance团队总结出了一系列可以提高网站速度的方法。可以分…

蒙特卡罗方法入门

本文通过五个例子&#xff0c;介绍蒙特卡罗方法&#xff08;Monte Carlo Method&#xff09;。一、概述蒙特卡罗方法是一种计算方法。原理是通过大量随机样本&#xff0c;去了解一个系统&#xff0c;进而得到所要计算的值。它非常强大和灵活&#xff0c;又相当简单易懂&#xf…

面向业务的微服务消息总线

源宝导读&#xff1a;移动PaaS项目的异步场景中&#xff0c;随着订阅主题数的增加&#xff0c;会出现开发维护成本高、管理难度大等问题&#xff0c;本文将分享如何通过构建面向业务的微服务消息总线应对这些问题。一、背景面向业务的消息总线本质上是对消息队列进行二次封装&a…

java locale.us_JAVA实现国际化

## 1 Java国际化的思路Java程序的国际化的思路是将程序中的标签、提示等信息放在资源文件中&#xff0c;程序需要支持哪些国家、语言环境&#xff0c;就对应提供相应的资源文件。资源文件是key-value对&#xff0c;每个资源文件中的key是不变的&#xff0c;但value则随不同国家…