26复杂类型比较,使用Compare .NET objects组件
关于比较对象,在"06判等对象是否相等"中大致可以总结为:
关于比较方法:
● 实例方法Equals(object obj)既可以比较值类型,也可以比较引用类型
● 静态方法Equals(object objA, object objB),比较值类型
● 静态方法ReferenceEquals(object objA, object objB),比较引用类型
● 比较引用类型可以用==,比较值类型不能用==
关于比较原则:
● 值类型比较的是值
● 引用类型比较的是引用地址
对于复杂类型,无论是复杂值类型(比如结构)还是复杂引用类型(包含值类型成员),经常要重写System.Object中的虚方法Equals(object obj)。比如,针对复杂值类型,可能这样重写:
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
RuntimeType type = (RuntimeType) base.GetType();
RuntimeType type2 = (RuntimeType) obj.GetType();
if (type2 != type) //比较两个对象是否是同一类型
{
return false;
}
object a = this;
if (CanCompareBits(this)) //对象成员如果存在对于堆的引用返回false
{
return FastEqualsCheck(a, obj);
}
//反射获取值类型的所有字段
FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < fields.Length; i++) //遍历字段,对各个字段进行比较
{
object obj3 = ((RtFieldInfo) fields[i]).UnsafeGetValue(a);
object obj4 = ((RtFieldInfo) fields[i]).UnsafeGetValue(obj);
if (obj3 == null)
{
if (obj4 != null)
{
return false;
}
}
else if (!obj3.Equals(obj4))
{
return false;
}
}
return true;
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
而现在,在NuGet上输入"Compare .NET objects",可以获取到该组件,对任何.NET对象进行比较、列出各个属性的值甚至自定义比较规则。

比较复杂类型:包含值类型成员
public class Teacher
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime JoinTime { get; set; }
public TeacherClass TeacherClass { get; set; }
}
public enum TeacherClass
{
[Description("执教5年以上")]
FirstClass = 0,
[Description("执教3年以上")]
SecondClass,
[Description("执教1年以上")]
ThirdClass
}
主程序:
Teacher teacher1 = new Teacher(){Id=1,JoinTime = new DateTime(2014,1,1),Name = "张老师",TeacherClass = TeacherClass.FirstClass};
Teacher teacher2 = new Teacher() { Id = 2, JoinTime = new DateTime(2014, 1, 2), Name = "李老师", TeacherClass = TeacherClass.SecondClass };
//获取Teacher属性的个数
int propertyCount = typeof (Teacher).GetProperties().Length;
//创建比较规则
CompareLogic compareLogic = new CompareLogic()
{
Config = new ComparisonConfig()
{
MaxDifferences = propertyCount//MaxDifferences的默认值是1
}
};
bool result = compareLogic.Compare(teacher1, teacher2).AreEqual;
Console.Write(result);
Console.ReadKey();
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
结果:false
比较复杂类型,并列出2个比较对象所有属性的值
Teacher teacher1 = new Teacher(){Id=1,JoinTime = new DateTime(2014,1,1),Name = "张老师",TeacherClass = TeacherClass.FirstClass};
Teacher teacher2 = new Teacher() { Id = 2, JoinTime = new DateTime(2014, 1, 2), Name = "李老师", TeacherClass = TeacherClass.SecondClass };
//获取Teacher属性的个数
int propertyCount = typeof (Teacher).GetProperties().Length;
//创建比较规则
CompareLogic compareLogic = new CompareLogic()
{
Config = new ComparisonConfig()
{
MaxDifferences = propertyCount//MaxDifferences的默认值是1
}
};
//获取2个比较对象的不同之处
List<Difference> differences = compareLogic.Compare(teacher1, teacher2).Differences;
StringBuilder sb = new StringBuilder();
foreach (Difference diff in differences)
{
sb.AppendLine("属性名称:" + diff.PropertyName);
sb.AppendLine("第一个对象值:" + diff.Object1Value);
sb.AppendLine("第二个对象值:" + diff.Object2Value + "\r\n");
}
using (StreamWriter outfile = new StreamWriter(@"F:\CompareObjects.txt"))
{
outfile.Write(sb.ToString());
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
结果:

比较复杂类型,并列出2个比较对象所有属性的值,对枚举属性自定义比较规则
需要一个自定义类,继承"Compare .NET objects"的BaseTypeComparer类,把打在枚举成员上的描述特性信息输出。
重写方法IsTypeMatch()用于判断2个比较对象的属性是否是枚举,如果是枚举,就采用重写方法CompareType()所定义的关于枚举属性的比较规则。
public class CustomEnumComparer : BaseTypeComparer
{
public CustomEnumComparer() : base(RootComparerFactory.GetRootComparer()){}
public override void CompareType(ComparisonResult result, object object1, object object2, string breadCrumb)
{
if (object1.ToString() != object2.ToString())
{
Difference difference = new Difference()
{
PropertyName = breadCrumb,
Object1Value = EnumHelper.GetDescription(object1),
Object2Value = EnumHelper.GetDescription(object2),
Object1 = new WeakReference(object1), //弱对象引用,即使被引用也可被垃圾回收
Object2 = new WeakReference(object2)
};
AddDifference(result,difference);
}
}
public override bool IsTypeMatch(Type type1, Type type2)
{
return TypeHelper.IsEnum(type1) && TypeHelper.IsEnum(type2);
}
}
//获取枚举类型的描述特性
public static class EnumHelper
{
public static string GetDescription(object enumMember)
{
//获取枚举类型的字段信息
FieldInfo fi = enumMember.GetType().GetField(enumMember.ToString());
//获取字段上的描述特性
IEnumerable<DescriptionAttribute> attributes = fi.GetCustomAttributes<DescriptionAttribute>(false);
return attributes.Any() ? attributes.ElementAt(0).Description : enumMember.ToString();
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
只需要把针对枚举属性的自定义类赋值给CompareLogic实例即可:
Teacher teacher1 = new Teacher(){Id=1,JoinTime = new DateTime(2014,1,1),Name = "张老师",TeacherClass = TeacherClass.FirstClass};
Teacher teacher2 = new Teacher() { Id = 2, JoinTime = new DateTime(2014, 1, 2), Name = "李老师", TeacherClass = TeacherClass.SecondClass };
//获取Teacher属性的个数
int propertyCount = typeof (Teacher).GetProperties().Length;
//创建比较规则
CompareLogic compareLogic = new CompareLogic()
{
Config = new ComparisonConfig()
{
MaxDifferences = propertyCount,//MaxDifferences的默认值是1
CustomComparers = new List<BaseTypeComparer>(){new CustomEnumComparer()}
}
};
//bool result = compareLogic.Compare(teacher1, teacher2).AreEqual;
//Console.Write(result);
//Console.ReadKey();
//获取2个比较对象的不同之处
List<Difference> differences = compareLogic.Compare(teacher1, teacher2).Differences;
StringBuilder sb = new StringBuilder();
foreach (Difference diff in differences)
{
sb.AppendLine("属性名称:" + diff.PropertyName);
sb.AppendLine("第一个对象值:" + diff.Object1Value);
sb.AppendLine("第二个对象值:" + diff.Object2Value + "\r\n");
}
using (StreamWriter outfile = new StreamWriter(@"F:\CompareObjects.txt"))
{
outfile.Write(sb.ToString());
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
结果:

参考资料:
26复杂类型比较,使用Compare .NET objects组件的更多相关文章
- Compare .NET Objects对象比较组件
Compare .NET Objects对象比较组件 阅读目录 1.Compare .NET Objects介绍 2. Compare .NET Objects注意事项 3.一个简单的使用案例 4.三 ...
- .NET平台开源项目速览(2)Compare .NET Objects对象比较组件
.NET平台开源项目速览今天介绍一款小巧强大的对象比较组件.可以更详细的获取2个对象的差别,并记录具体差别,比较过程和要求可以灵活配置. .NET开源目录:[目录]本博客其他.NET开源项目文章目录 ...
- 未能找到类型或命名空间“Compare”
在用vs2012 .net Framework4.5 Mvc3做一个MVCMusicStore 的例子时,遇到这样一个问题 解决办法: 具体原因也不是很清楚,据说是引用Compare做验证时会有二 ...
- 使用EF6.0出现:CS0029 无法将类型“System.Data.Entity.Core.Objects.ObjectContext”隐式转换为“System.Data.Objects.ObjectContext”错误
这是因为EF6.0重构了一些命名空间后,和VS原有的实体数据模型模板不一致了(ObjectContext context = ((IObjectContextAdapter)dataContext). ...
- Javascript学习1 - Javascript中的类型对象
原文:Javascript学习1 - Javascript中的类型对象 1.1关于Numbers对象. 常用的方法:number.toString() 不用具体介绍,把数字转换为字符串,相应的还有一个 ...
- Effective Java 第三版——61. 基本类型优于装箱的基本类型
Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...
- Java 常用对象-基本类型的封装类
2017-11-04 20:39:26 基本类型封装类:基本类型的封装类的好处是可以在对象中定义更多的功能方法操作该数据. 常用操作之一:用于基本数据类型与字符串的转换. 基本类型和包装类的对应: b ...
- Oracle Schema Objects(Schema Object Storage And Type)
One characteristic of an RDBMS is the independence of physical data storage from logical data struct ...
- Beyond Compare设置自定义过滤
Beyond Compare是一款优秀的专业级文件比较软件,利用它可以快速比较出文件之间的差异,以便于修改.整合.其中较强大的功能之一就是文件夹比较,面对海量的子文件夹以及文件,Beyond Comp ...
随机推荐
- UVA 10891 Game of Sum(区间DP(记忆化搜索))
题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem ...
- 利用sys.dm_db_index_physical_stats查看索引碎片等数据
我们都知道,提高sql server的数据查询速度,最有效的方法,就是为表创建索引,而索引在对数据进行新增,删除,修改的时候,会产生索引碎片,索引碎片多了,就需要重新组织或重新生成索引,以达到索引的最 ...
- 快速php日志,写内容到文件,把日志写到log文件
php 写内容到文件,把日志写到log文件 //记录日志:要写入文件的文件名(可以是任意文件名),如果文件不存在,将会创建一个.log.txt位置在项目的根目录下. $file = 'log.txt' ...
- 安装VM虚拟机提示 尝试创建目录 C:\Public\documents\SharedVirtual Machines 时发生错误解决方法
把Windows Defender安全中心的“受控制文件夹的访问”给关闭了,然后就可以顺利安装上了. 作者:耑新新,发布于 博客园 转载请注明出处,欢迎邮件交流:zhuanxinxin@foxmai ...
- Hadoop案例(十一)MapReduce的API使用
一学生成绩---增强版 数据信息 computer,huangxiaoming,,,,,,, computer,xuzheng,,,,, computer,huangbo,,,, english,zh ...
- C语言:奇偶归一猜想
1.奇偶归一猜想——求多少步归一.(10分) 题目内容: 奇偶归一猜想——对于每一个正整数,如果它是奇数,则对它乘3再加1,如果它是偶数,则对它除以2,如此循环,最终都能够得到1. 如n = 11,得 ...
- 回文树练习 Part1
URAL - 1960 Palindromes and Super Abilities 回文树水题,每次插入时统计数量即可. #include<bits/stdc++.h> using ...
- CSUOJ 1726 你经历过绝望吗?两次!BFS+优先队列
Description 4月16日,日本熊本地区强震后,受灾严重的阿苏市一养猪场倒塌,幸运的是,猪圈里很多头猪依然坚强存活.当地15名消防员耗时一天解救围困的"猪坚强".不过与在废 ...
- Docker应用系列(六)| 如何去掉sudo及避免权限问题
一.如何在使用docker时去掉sudo 1.添加账户 $ sudo groupadd docker 2.授权给docker账户 sudo gpasswd -a yourname docker 3.重 ...
- Linux-CentOs7-svn安装及钩子配置
做个svn的教程 首先进入test目录下,新建一个svn目录,准备做svn测试cd /testmkdir svncd svn然后使用yum安装svn,这里就不使用编译安装了,这玩意只要能用就行,版本无 ...