C#之相等比较

  C#中的对象都继承自System.Object对象,分为引用类型和值类型两种,所以对象的相等比较而言就分两种,一种是比较引用,一种是比较值。System.Object默认提供了三个方法来进行对象的相等比较:静态的ReferenceEquals()和Equals()的两个版本,加上“==”运算符共有四种来进行对象相等比较的方法。

  相等比较的方法:静态的ReferenceEquals()、Equals()静态方法、Equals()虚方法(子类可以去重写)和“==”运算符。

  相等比较分类:引用类型比较(类的实例)、值类型比较(基本数据类型,结构或者枚举的实例)。

  但对于引用类型和值类型而言,同一个方法它们的内部比较逻辑是不一样的,下面进行下简单的介绍。

一、引用类型相等比较

1、静态的ReferenceEquals()

  ReferenceEquals()是一个静态方法,比较两个对象是否引用自同一个地址,是则返回true,否则返回false

  调用方法:ReferenceEquals(obj1,obj2)

  比较原则:1)、obj1和obj2同为null,则返回true

         2)、obj1和obj2只有一个为null,则返回false

       3)、obj1和obj2均不为null时,比较两个对象的引用地址,是则返回true,不是则返回false

  例子:

    SomeClass x,y;

    x = new SomeClass();

    y = new SomeClass();

    z = y;

    Boolean result1 = ReferenceEquals(null,null);  //return true

    Boolean result2 = ReferenceEquals(null,x);   //return false

    Boolean result3 = ReferenceEquals(x,y);    //return false

    Boolean result4 = ReferenceEquals(y,z);    //return true

2、虚拟的Equals()方法

  System.Object()的虚拟的Equals()方法也是比较引用的,但是因为它是虚拟的,所以继承的子类可以重写该方法以实现按值来比较对象,在重写Equals()方法时最好重写对象的GetHashCode()方法.

View Code
namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Point p1 = new Point(5, 2);
            Point p2 = new Point(5, 2);
            Point3D p3 = new Point3D(5, 2, 1);
            Point3D p4 = new Point3D(5, 2, 1);

            if (p1.Equals(p2))
                Console.WriteLine("p1 is equals p2");
            if (p3.Equals(p4))
                Console.WriteLine("p3 is equals p4");

            if (!p1.Equals(p3))
                Console.WriteLine("p1 is not equals p3");

            if (!p3.Equals(p1))
                Console.WriteLine("p3 is not equals p1");
        }
    }

    public class Point
    {
        private Int32 x;
        private Int32 y;

        public Point()
        {
            this.x = 0;
            this.y = 0;
        }
        public Point(Int32 _x, Int32 _y)
        {
            this.x = _x;
            this.y = _y;
        }

        public Int32 X
        {
            get { return x; }
            set { x = value; }
        }

        public Int32 Y
        {
            get { return y; }
            set { y = value; }
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            if (this.GetType() != obj.GetType())
                return false;


            return Equals((Point)obj);
        }

        public override int GetHashCode()
        {
            return x ^ y;
            //return base.GetHashCode();
        }

        public override string ToString()
        {
            return String.Format("X:{0},Y:{1}", this.x, this.y);
            //return base.ToString();
        }

        private bool Equals(Point p)
        {
            return (this.x == p.x) && (this.y == p.y);
        }
    }

    public class Point3D : Point
    {
        private Int32 z;
        public Int32 Z
        {
            get { return this.z; }
            set { z = value; }
        }

        public Point3D()
            : base()
        {
            this.z = 0;
        }

        public Point3D(Int32 _x, Int32 _y, Int32 _z)
            : base(_x, _y)
        {
            this.z = _z;
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;
            if (GetType() != obj.GetType())
                return false;

            Point3D p3d = obj as Point3D;

            if (p3d.z != this.z)
                return false;

            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode() ^ z;
        }

        public override string ToString()
        {
            return String.Format("X:{0},Y:{1},Z:{2}", base.X, base.Y, Z);
        }
    }
}

3、静态的Equals()方法

  Eauals()静态方法的比较原则是按照引用的方式比较,再调用对象的Equals()方法的实例版本进行比较,所以在重写对象的Equals()方法时,其实已经间接的重写了静态的Equals()方法。

  调用方法:Equals(obj1,obj2)

  比较原则:1)、obj1和obj2均为null,则返回true

       2)、obj1和obj2中只有一个为null,则返回false

       3)、如果obj1和obj2两个引用不指向同一个对象,则返回false

       4)、如果obj1和obj2两个引用指向同一个对象,则调用它们的Equals()方法的实例版本进行比较

4、“==”比较运算符

  在默认情况下,==运算符对引用类型比较的是两个对象指向的引用是否是同一个对象,但是作为一个自定义的复杂类,可以自己重写适合自己的“==”运算符,在重写“==”时必须同时重写“!=”运算符。

  例1:在没有重写“==”时,我们看下两个类的“==”的比较结果(比较是否指向同一个引用)

View Code
namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Point p1 = new Point(5, 2);
            Point p2 = new Point(5, 2);
            Point p21 = p1;

            if (p1.Equals(p2))
                Console.WriteLine("p1 is equals p2");

            if (!(p1 == p2))
                Console.WriteLine("p1 is not == p2");

            if (p1 == p21)
                Console.WriteLine("p1 is == p21");
        }
    }

    public class Point
    {
        private Int32 x;
        private Int32 y;

        public Point()
        {
            this.x = 0;
            this.y = 0;
        }
        public Point(Int32 _x, Int32 _y)
        {
            this.x = _x;
            this.y = _y;
        }

        public Int32 X
        {
            get { return x; }
            set { x = value; }
        }

        public Int32 Y
        {
            get { return y; }
            set { y = value; }
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            if (this.GetType() != obj.GetType())
                return false;


            return Equals((Point)obj);
        }

        public override int GetHashCode()
        {
            return x ^ y;
            //return base.GetHashCode();
        }

        public override string ToString()
        {
            return String.Format("X:{0},Y:{1}", this.x, this.y);
            //return base.ToString();
        }

        private bool Equals(Point p)
        {
            return (this.x == p.x) && (this.y == p.y);
        }
    }
}

  运算结果:

  例2:我们重写“==”运算符(比较两个对象对应值是否相等),这时再看下结果

View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Point p1 = new Point(5, 2);
            Point p2 = new Point(5, 2);
            Point p21 = p1;

            if (p1.Equals(p2))
                Console.WriteLine("p1 is equals p2");

            if (p1 == p2)
                Console.WriteLine("p1 is == p2");

            if (p1 == p21)
                Console.WriteLine("p1 is == p21");
        }
    }

    public class Point
    {
        private Int32 x;
        private Int32 y;

        public Point()
        {
            this.x = 0;
            this.y = 0;
        }
        public Point(Int32 _x, Int32 _y)
        {
            this.x = _x;
            this.y = _y;
        }

        public Int32 X
        {
            get { return x; }
            set { x = value; }
        }

        public Int32 Y
        {
            get { return y; }
            set { y = value; }
        }

        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;

            if (this.GetType() != obj.GetType())
                return false;


            return Equals((Point)obj);
        }

        /// <summary>
        /// 重写相等运算符
        /// </summary>
        public static Boolean operator ==(Point p1, Point p2)
        {
            return (p1.x == p2.x) && (p1.y == p2.y);
        }

        /// <summary>
        /// 重写不相等运算符
        /// </summary>
        public static Boolean operator !=(Point p1, Point p2)
        {
            return !(p1.x == p2.x) && (p1.y == p2.y);
        }

        public override int GetHashCode()
        {
            return x ^ y;
            //return base.GetHashCode();
        }

        public override string ToString()
        {
            return String.Format("X:{0},Y:{1}", this.x, this.y);
            //return base.ToString();
        }

        private bool Equals(Point p)
        {
            return (this.x == p.x) && (this.y == p.y);
        }
    }
}

  运算结果:

 

二、值类型相等比较

1、静态的ReferenceEquals()

  ReferenceEquals()方法用于比较引用,在比较之前,C#会先通过装箱技术对每个值类型参数进行分别装箱,这样ReferenceEquals()方法进行比较时得到的结果永远时false,所以用ReferenceEquals()来比较值类型是没有什么意义的。

2、虚拟的Equals()方法、静态的Equals()方法和“==”运算符

  对于值类型,这三个方法默认都是进行值比较的。

View Code
namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {

            Int32 a = 5;
            Int32 b = 5;

            if (a.Equals(b))
                Console.WriteLine("a is equals b");
            if (a == b)
                Console.WriteLine("a is == b");

            if (Equals(a, b))
                Console.WriteLine("a is equals b");

            if (!ReferenceEquals(a, b))
                Console.WriteLine("a is not ReferenceEquals b");
        }
    }
}

    

转载于:https://www.cnblogs.com/NaughtyBoy/archive/2012/06/07/2538464.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值