C#高级编程之比较对象的相等性

目录

 

背景介绍:

比较引用类型的相等性:

1. 比较运算符(==):

2.ReferenceEquals()方法:

3.Equal()虚方法和静态Equals()方法:

2.比较值类型的相等性。

总结:


背景介绍:

对象相等机制有所不同,这取决于比较的是引用类型(类的实例)还是值类型(基本数据类型、结构或枚举的实例)。在讲解值类型跟引用类型相等性之前。有必要介绍一张图。

下面分别介绍引用类型和值类型的相等性。

比较引用类型的相等性:

System.Object定义了3个不同的方法来比较对象的相等性:ReferenceEquals()、Equals虚方法和静态方法、比较运算符(==)。这里我首先介绍比较运算符(==)

1. 比较运算符(==):

比较运算符实际比较的是栈上地址值,而实际上我们更加关心该栈单元所存储的值。所以一般会对"=="进行运算符的重载。

对于引用类型,栈上存储对实例对象的引用,堆上存放对象的实际值。通过重载运算符,"=="实现比较对象实际单元值。如上图中student1对象的属性值 21 "zhangsan" 和student2对象的属性值 21 "zhangsan".最终的返回结果为:同一对象

{
    class DemoObjectEquals
    {
     
        static void Main(string[] args)
        {
            Student student1 = new Student(21,"zhangsan");
            Student student2 = new Student(21, "zhangsan");
            if (student1 == student2)
            {
                Console.WriteLine("同一对象");
            }
            else
            {
                Console.WriteLine("不是同一对象");
            }
            Console.ReadKey();

        }
    }

     class Student
    {
        private string name;
        private int age;

        public string Name { get => name; set => name = value; }
        public int Age { get => age; set => age = value; }
        public static bool operator ==(Student student1, Student student2)
        {
            //  true如果objA是相同的实例作为objB或如果两者均null; 否则为false
            if (object.ReferenceEquals(student1, student2))
            {
                return true;

            }
            else if (object.ReferenceEquals(student1, null) || (object.ReferenceEquals(student2, null)))
            {
                return false;
            }
            return student1.Equals(student2);
        }
        public static bool operator !=(Student student1, Student student2)
        {
            return !(student1 == student2);
        }
        public override bool Equals(object obj)
        {
            Student student = (Student)obj;
            return (this.Age == student.Age && (this.Name == student.Name));
        }

        public override int GetHashCode()
        {
            return (this.Age.GetHashCode() + this.Name.GetHashCode());
        }
        public Student(int age,string name)
        {
            this.age = age;
            this.name = name;

        }
    }

2.ReferenceEquals()方法:

该方法为静态方法,不能重写。其用于测试两个引用是否指向类的同一实例,特别是两个引用在栈上的值(即在内存中的地址)是否相同。其函数签名如下:

 //
        // 摘要:
        //     确定指定的 System.Object 实例是否是相同的实例。
        //
        // 参数:
        //   objA:
        //     要比较的第一个对象。
        //
        //   objB:
        //     要比较的第二个对象。
        //
        // 返回结果:
        //     true如果objA是相同的实例作为objB或如果两者均null; 否则为false。
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public static bool ReferenceEquals(Object objA, Object objB);

3.Equal()虚方法和静态Equals()方法:

前面讲到"=="的重载。当在栈上两实例对象的引用值不相等时,具体对其实例对象相关属性值(对象实际单元值)判断时,通过重写Equal()虚方法来实现当前this对应于待比较objB的实例属性值是否相等。在重写Equal虚方法时,对应的GetHashCode()也要重写。两个方法对应的函数签名如下:

  //
        // 摘要:
        //     确定指定的对象实例是否被视为相等。
        //
        // 参数:
        //   objA:
        //     要比较的第一个对象。
        //
        //   objB:
        //     要比较的第二个对象。
        //
        // 返回结果:
        //     如果对象被视为相等,则为 true,否则为 false。 如果 objA 和 objB 均为 null,此方法将返回 true。
        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public static bool Equals(Object objA, Object objB);
---------------------------------------------------------------------------

   // 摘要:
        //     确定指定的对象是否等于当前对象。
        //
        // 参数:
        //   obj:
        //     要与当前对象进行比较的对象。
        //
        // 返回结果:
        //     如果指定的对象等于当前对象,则为 true,否则为 false。
        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public virtual bool Equals(Object obj);

我们可以看到静态的Equals方法除了函数类型和参数个数不同外,还有一点就是静态方法多了对于Null情况的判定。

2.比较值类型的相等性。

对于值类型的比较,对应int a=1,int b=1.通过if(a==b ){}来判定的是实际栈存储的值是否相等,即1是否等于1.

"=="本身最初还是比较的栈地址值(最初是不等的)如上图:0x4524,0x4525。而.NET本身帮我们做了一些事情。其在System.VauleType类中重载了实例方法Equals(),这样就又回到了上面讲述的引用类型中Equal方法重载的情况。

总结:

最原始的比较都是比较实际地址值的。(未进行任何包装以及重载)

对于值类型和引用类型判断相等时,规则如下:ReferenceEquals用于比较引用(栈上地址值),Equals用于重写并实现值比较(实对象实例内容)。

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值