分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 技术分享

.NET中如何深度判断2个对象相等

发布时间:2023-09-06 02:27责任编辑:熊小新关键词:.NET

背景

最近在群里,有人问如何深度比较2个对象相等,感觉很有意思,就自己研究了一下,并写了一个开源的小类库,地址如下https://github.com/lamondlu/ObjectEquality。

如果想直接使用这个类库,可以使用Nuget进行安装

Install-Package ObjectEquality

对象比较有几种情况

  1. 对象是值类型或者String,这里仅需要判断值是否相等
  2. 对象是Struct,需要判断Struct的每个字段是否一致
  3. 对象是集合,需要判断对应位置的对象是否相等
  4. 对象是数组,需要判断对应位置的对象是否相等
  5. 对象是Class, 需要判断Class的每个字段是否一致

这里可能有缺漏,大家可以帮我补充。

编写代码

这里我首先创建了一个IEquality接口,在其中定义了一个IsEqual方法,这个方法就是判断2个对象是否一致的方法。后面我会针对上面说明的几种对比场景,分别创建对应的实现类。

 ???public interface IEquality ???{ ???????Func<object, bool> MatchCondition { get; } ???????bool IsEqual(object source, object target); ???}

这里MatchCondition是一个委托,它定义了当前对比类的匹配条件。

第二步,我们针对上述的几种对比场景,创建对应的实现类

值类型相等判断实现类

 ???internal class ValueTypeEquality : IEquality ???{ ???????public Func<object, bool> MatchCondition ???????{ ???????????get ???????????{ ???????????????return p => p.GetType().IsValueType || p.GetType() == typeof(string); ???????????} ???????} ???????public bool IsEqual(object source, object target) ???????{ ???????????return source.Equals(target); ???????} ???}

值类型的判断比较简单,直接调用Object类的Equals方法即可。

String类型虽然不是值类型,但是这里我们需要把它归到值类型中。

Struct相等判断实现类

 ???internal class StructEquality : IEquality ???{ ???????public Func<object, bool> MatchCondition ???????{ ???????????get ???????????{ ???????????????return p => p.GetType().IsValueType ????????????????????&& !p.GetType().IsPrimitive ????????????????????&& !p.GetType().IsEnum; ???????????} ???????} ???????public bool IsEqual(object source, object target) ???????{ ???????????var type = source.GetType(); ???????????foreach (var prop in type.GetProperties()) ???????????{ ???????????????var equality = EqualityCollection.Equalities ???????????????????.First(p => p.MatchCondition(prop.GetValue(source))); ???????????????var result = equality.IsEqual(prop.GetValue(source), ???????????????????prop.GetValue(target)); ???????????????if (!result) ???????????????{ ???????????????????return false; ???????????????} ???????????} ???????????return true; ???????} ???} ??

这里我们读取了Struct中的每个属性,分别进行判断,如果有一个判断失败,即认为2个Struct对象不相等。

这里EqualityCollection是判断器集合,后续会添加这个类的代码。

集合相等判断实现类

 ???internal class GenericCollectionEquality : IEquality ???{ ???????public Func<object, bool> MatchCondition ???????{ ???????????get ???????????{ ???????????????return p => p.GetType().IsGenericType; ???????????} ???????} ???????public bool IsEqual(object source, object target) ???????{ ???????????var type = source.GetType(); ???????????var genericType = type.GetGenericArguments()[0]; ???????????var genericCollectionType = typeof(IEnumerable<>).MakeGenericType(genericType); ???????????if (type.GetInterfaces().Any(p => p == genericCollectionType)) ???????????{ ???????????????var countMethod = type.GetMethod("get_Count"); ???????????????var sourceCount = (int)countMethod.Invoke(source, null); ???????????????var targetCount = (int)countMethod.Invoke(target, null); ???????????????if (sourceCount != targetCount) ???????????????{ ???????????????????return false; ???????????????} ???????????????var sourceCollection = (source as IEnumerable<object>).ToList(); ???????????????var targetCollection = (target as IEnumerable<object>).ToList(); ???????????????for (var i = 0; i < sourceCount; i++) ???????????????{ ???????????????????var equality = EqualityCollection.Equalities.First(p => p.MatchCondition(sourceCollection[i])); ???????????????????var result = equality.IsEqual(sourceCollection[i], targetCollection[i]); ???????????????????if (!result) ???????????????????{ ???????????????????????return false; ???????????????????} ???????????????} ???????????} ???????????return true; ???????} ???}

这里我们首先判断了集合的元素的数量是否一致,如果不一致,即这2个集合不相等。如果一致,我们继续判断对应位置的每个元素是否一致,如果全部都一直,则2个集合相当,否则2个集合不相等。

数组相等判断实现类

 ???internal class ArrayEquality : IEquality ???{ ???????public Func<object, bool> MatchCondition ???????{ ???????????get ???????????{ ???????????????return p => p.GetType().IsArray; ???????????} ???????} ???????public bool IsEqual(object source, object target) ???????{ ???????????Array s = source as Array; ???????????Array t = target as Array; ???????????if (s.Length != t.Length) ???????????{ ???????????????return false; ???????????} ???????????????????????for (var i = 0; i < s.Length; i++) ???????????{ ???????????????var equality = EqualityCollection.Equalities ???????????????????.First(p => p.MatchCondition(s.GetValue(i))); ???????????????var result = equality.IsEqual(s.GetValue(i), t.GetValue(i)); ???????????????if (!result) ???????????????{ ???????????????????return false; ???????????????} ???????????} ???????????return true; ???????} ???}

数组相等的判断类似集合,我们首先判断数组的长度是否一致,然后判断对应位置的元素是否一致。

类判断相等实现类

 ???internal class ClassEquality : IEquality ???{ ???????public Func<object, bool> MatchCondition ???????{ ???????????get ???????????{ ???????????????return p => p.GetType().IsClass; ???????????} ???????} ???????public bool IsEqual(object source, object target) ???????{ ???????????var type = source.GetType(); ???????????foreach (var prop in type.GetProperties()) ???????????{ ???????????????var equality = EqualityCollection.Equalities ???????????????????.First(p => p.MatchCondition(prop.GetValue(source))); ???????????????var result = equality.IsEqual(prop.GetValue(source), prop.GetValue(target)); ???????????????if (!result) ???????????????{ ???????????????????return false; ???????????????} ???????????} ???????????return true; ???????} ???}

添加判断相等实现类集合

 ???public static class EqualityCollection ???{ ???????public static readonly List<IEquality> Equalities = new List<IEquality> { ???????????new StructEquality(), ???????????new ValueTypeEquality(), ???????????new ArrayEquality(), ???????????new GenericCollectionEquality(), ???????????new ClassEquality() ???????}; ???}

这里我们定义了一个静态类,来存储程序中使用的所有判断器。

这里在判断器集合中,实现类的其实是有顺序的,StructEquality必须要放到ValueTypeEquality的前面,因为Struct也是值类型,如果不放到最前面,会导致判断失败。

创建判断器入口类

 ???public class ObjectEquality ???{ ???????public bool IsEqual(object source, object target) ???????{ ???????????if (source.GetType() != target.GetType()) ???????????{ ???????????????return false; ???????????} ???????????if (source == null && target == null) ???????????{ ???????????????return true; ???????????} ???????????else if (source == null && target != null) ???????????{ ???????????????return false; ???????????} ???????????else if (source != null && target == null) ???????????{ ???????????????return false; ???????????} ???????????var equality = EqualityCollection.Equalities ???????????????.First(p => p.MatchCondition(source)); ???????????return equality.IsEqual(source, target); ???????} ???}

前面所有实现类的访问级别都是Internal, 所以我们需要创建一个判断器入口类, 外部只能通过ObjectEquality类的实例来实现判断相等。

最终效果

下面我列举几个测试用例,看看效果是不是我们想要的

对比Struct

 ???public struct DemoStruct ???{ ???????public int Id { get; set; } ???????public string Name { get; set; } ???}
 ???var a = new DemoStruct(); ???a.Id = 1; ???a.Name = "Test"; ???var b = new DemoStruct(); ???b.Id = 1; ???b.Name = "Test"; ???????var c = new DemoStruct(); ???b.Id = 2; ???b.Name = "Test"; ???????ObjectEquality objectEquality = new ObjectEquality(); ???objectEquality.IsEqual(a,b); //true ???objectEquality.IsEqual(a,c); //false

对比类

 ???public class SimpleClass ???{ ???????public int Id { get; set; } ???????public string Name { get; set; } ???}
 ???var a = new SimpleClass ???{ ???????Id = 1, ???????Name = "A" ???}; ???var b = new SimpleClass ???{ ???????Id = 1, ???????Name = "A" ???}; ???????var c = new SimpleClass ???{ ???????Id = 2, ???????Name = "A" ???}; ???????ObjectEquality objectEquality = new ObjectEquality(); ???objectEquality.IsEqual(a,b); //true ???objectEquality.IsEqual(a,c); //false

对比数组

 ???var a = new int[] { 1, 2, 3 }; ???var b = new int[] { 1, 2, 3 }; ???var c = new int[] { 1, 1, 2 }; ????????ObjectEquality objectEquality = new ObjectEquality(); ???objectEquality.IsEqual(a,b); //true ???objectEquality.IsEqual(a,c); //false

.NET中如何深度判断2个对象相等

原文地址:https://www.cnblogs.com/lwqlun/p/10159770.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved