关于比较对象,在"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; }

结果:

 

参考资料:

Compare .NET Objects Tutorial

26复杂类型比较,使用Compare .NET objects组件的更多相关文章

  1. Compare .NET Objects对象比较组件

    Compare .NET Objects对象比较组件 阅读目录 1.Compare .NET Objects介绍 2. Compare .NET Objects注意事项 3.一个简单的使用案例 4.三 ...

  2. .NET平台开源项目速览(2)Compare .NET Objects对象比较组件

    .NET平台开源项目速览今天介绍一款小巧强大的对象比较组件.可以更详细的获取2个对象的差别,并记录具体差别,比较过程和要求可以灵活配置. .NET开源目录:[目录]本博客其他.NET开源项目文章目录 ...

  3. 未能找到类型或命名空间“Compare”

    在用vs2012  .net Framework4.5  Mvc3做一个MVCMusicStore 的例子时,遇到这样一个问题 解决办法: 具体原因也不是很清楚,据说是引用Compare做验证时会有二 ...

  4. 使用EF6.0出现:CS0029 无法将类型“System.Data.Entity.Core.Objects.ObjectContext”隐式转换为“System.Data.Objects.ObjectContext”错误

    这是因为EF6.0重构了一些命名空间后,和VS原有的实体数据模型模板不一致了(ObjectContext context = ((IObjectContextAdapter)dataContext). ...

  5. Javascript学习1 - Javascript中的类型对象

    原文:Javascript学习1 - Javascript中的类型对象 1.1关于Numbers对象. 常用的方法:number.toString() 不用具体介绍,把数字转换为字符串,相应的还有一个 ...

  6. Effective Java 第三版——61. 基本类型优于装箱的基本类型

    Tips 书中的源代码地址:https://github.com/jbloch/effective-java-3e-source-code 注意,书中的有些代码里方法是基于Java 9 API中的,所 ...

  7. Java 常用对象-基本类型的封装类

    2017-11-04 20:39:26 基本类型封装类:基本类型的封装类的好处是可以在对象中定义更多的功能方法操作该数据. 常用操作之一:用于基本数据类型与字符串的转换. 基本类型和包装类的对应: b ...

  8. Oracle Schema Objects(Schema Object Storage And Type)

    One characteristic of an RDBMS is the independence of physical data storage from logical data struct ...

  9. Beyond Compare设置自定义过滤

    Beyond Compare是一款优秀的专业级文件比较软件,利用它可以快速比较出文件之间的差异,以便于修改.整合.其中较强大的功能之一就是文件夹比较,面对海量的子文件夹以及文件,Beyond Comp ...

随机推荐

  1. IntelliJ IDEA + Tomcat ;On Upate Action 与 On Frame Deactivation

    On Upate Action 与 On Frame Deactivation  这两个选项的设置,依赖于 项目的部署方式 是war包 还是 exploded ,看下面的gif: 这里实在是太灵活了, ...

  2. P2184 【贪婪大陆】

    看到全是线段树或者树状数组写法,就来提供一发全网唯一cdq分治三维偏序解法吧 容易发现,这个题的查询就是对于每个区间l,r,查询有多少个修改区间li,ri与l,r有交集 转化为数学语言,就是查询满足l ...

  3. set IDENTITY_INSERT on 和 off 的设置

    qlserver 批量插入记录时,对有标识列的字段要设置 set IDENTITY_INSERT 表名 on,然后再执行插入记录操作;插入完毕后恢复为 off 设置 格式:  set IDENTITY ...

  4. 涨姿势系列之——内核环境下花式获得CSRSS进程id

    这个是翻别人的代码时看到的,所以叫涨姿势系列.作者写了一个获取CSRSS进程PID的函数,结果我看了好久才看懂是这么一个作用.先放上代码 HANDLE GetCsrPid() { HANDLE Pro ...

  5. 一步一步学习IdentityServer3 (14) 启用Https

    申领一个CA证书,我用了一个腾讯的免费证书night-c.cn,这是腾讯云买域名送的一个证书 是单域名,非泛域名 1:安装证书  IIS选择证书 2:将证书加载到Identityserver3中,并启 ...

  6. IE6 验证码刷新失败显示空白解决办法

    原因:点击a标签看不清?换图片 结果验证码显示的空白! 解决办法:在对应的点击事件最后加上return false 即可解决问题. 下面是HTML源码: <p class="regis ...

  7. Codeforces Round #213 (Div. 1) B - Free Market 思维+背包 好题

    B - Free Market 思路:这个题怎么说呢,迷惑性很大,题目里说了交换了两个集合的时候如果有相同元素不能交换,感觉如果没 这句话能很快写出来, 其实当交换的两个集合有重复元素的时候只要交换那 ...

  8. Looksery Cup 2015 F - Yura and Developers 单调栈+启发式合并

    F - Yura and Developers 第一次知道单调栈搞出来的区间也能启发式合并... 你把它想想成一个树的形式, 可以发现确实可以启发式合并. #include<bits/stdc+ ...

  9. LeetCode 80. 删除排序数组中的重复项 II

    LeetCode 80. 删除排序数组中的重复项 II

  10. 【转】 LINUX中IPTABLES和TC对端口的带宽限制 端口限速

    不管是iptables还是tc(traffic control)功能都很强大,都是与网络相关的工具,那么我们就利用这两个工具来对端口进行带宽的限制. 1.使用命令ifconfig查看服务器上的网卡信息 ...