C#相等比较

相等的比较:
值相等和引用相等。
值相等:两个值在某种意义上是想等的。
引用相等:两个引用指向完全相同的对象。
默认情况下:
值类型使用值相等。
引用类型使用引用相等。

 1.标准等值比较协议

  • ==和!=
  • object对象Equals虚方法
  • IEquatble<T>接口

==和!=

很多的例子中都使用了标准的==和!=运算符进行相等/不相等的比较。而==与!=的特殊性在于它们的运算符,因此它们是静态解析的(实际上,它们的本身就是静态函数)。因此使用==和!=时,c#会在编译时根据类型确认时哪一个函数执行比较操作,且这里没有任何虚行为。

 {
                int x = 5;
                int y = 5;
                Console.WriteLine(x==y);//true
                //这个例子编译器会把==绑定在int类型上,int是值类型,所以此时==进行的是值类型比较,所有为true
            }
            {
                object x = 5;
                object y = 5;
                Console.WriteLine(x == y);//false
               //这个例子编译器会把==绑定在object类型上,object是引用类型,所以此时==进行的是引用比较,所有为false
            }

Object对象Equals虚方法

Equals定义在System.Object上的方法,所以所有的类型都支持这个方法。

Equals在运行时根据对象的实例类型解析的。如果你这个是对象是int类型的那么它实际调用的是int的Equals方法。对于引用类型Equals默认进行引用相等比较,而对于结构体,Equals会对结构体的每一个字段的Equals进行结构化比较。

{
                object x = 5;
                object y = 5;
                Console.WriteLine(x.Equals(y));//false
            }

object.Equals静态方法

object 的类提供一个静态的辅助方法,该方法正是实现上一个例子中的AreEqual操作。虽然它们的名字与虚方法相同,但是它们不会冲突。

ps:这个方法可以提供null值的相等比较

                object x = 1, y = 2;
                object.Equals(x, y);
                x = null;
                object.Equals(x, y);
                y = null;
                object.Equals(x, y);

object.Equals在泛型中的应用

 public class Test<T>
        {
            T _value;
            public void SetValue(T value)
            {
                if (!object.Equals(value,_value))
                {
                    _value = value;
                }
            }
        }

object.ReferenceEquals

这个方法通常用于“自比”

                StringBuilder builder1 = new StringBuilder();
                StringBuilder builder2 = new StringBuilder();
                Console.WriteLine(object.ReferenceEquals(builder1, builder1));//true
                Console.WriteLine(object.ReferenceEquals(builder1, builder2));//false

 

IEquatable<T>接口

将 IEquatable<T> 接口的类型参数替换为实现此接口的类型。 如果实现 IEquatable<T>,还应覆盖 Equals(Object) 和 GetHashCode() 的基类实现,使其行为与 Equals(T) 方法的行为一致。 如果确实要重写 Equals(Object),则也会在对类的静态 Equals(System.Object, System.Object) 方法的调用中调用重写的实现。 此外,还应重载 == 和 != 运算符。这可以确保相等性的所有测试都返回一致的结果。

2.相等比较和自定义比较

默认的相等比较

  • 值类型采用相等比较
  • 引用类型采用引用相等比较

此外结构体的Equals方法默认采用的是结构体值相等。(它会比较结构体中的每个字段)

说到自定义比较有两种情况比较适用

  • 改变相等比较的含义
  • 提高结构相等比较的速度

ps:结构体默认的相等比较算法是比较慢的。通过重载Equals能够获得近20%的性能提升,重载==运算符并实现IEquatable<T>接口可以避免相等比较过程中的装箱操作,这样可以将速度再提高20%。

平常开发中用的结构体,都做到了上述优化的,比如说Datetime。

那么该如何重写相等语义呢。

  1. GetHashCode和Equals必须实现
  2. 重载==和!=(可选)
  3. 实现IEquatable<T>(可选)

例子:

public struct Area : IEquatable<Area>
    {
        public readonly int Measure1;
        public readonly int Measure2;
        public Area(int m1,int m2)
        {
            Measure1 = Math.Min(m1, m2);
            Measure2 = Math.Max(m1, m2);
        }
        public override bool Equals(object obj)
        {
            if (!(obj is Area)) return false;
            return Equals((Area)obj);
        }
        /// <summary>
        /// 由Json Bloch推荐的模式
        /// 
        /// </summary>
        /// <remarks>
        /// int hash=17;
        /// hash=hash*31+field1.GetHashCode();
        /// hash=hash*31+field2.GetHashCode();
        /// return hash;
        /// </remarks>
        /// <returns></returns>
        public override int GetHashCode() => Measure1 + Measure2 * 31;
        public override string ToString()
        {
            return (Measure1 + Measure2).ToString();
        }
        public bool Equals(Area other) => Measure1 == other.Measure1 && Measure2 == other.Measure2;

        /// <summary>
        /// 重载运算符
        /// </summary>
        /// <param name="a1"></param>
        /// <param name="a2"></param>
        /// <returns></returns>
        public static bool operator ==(Area a1, Area a2) => a1.Equals(a2);
        public static bool operator !=(Area a1, Area a2) => !a1.Equals(a2);
    }

测试

                Area area = new Area(5,3);
                Area area2 = new Area(3, 5);
                Console.WriteLine(area.Equals(area2));//true
                Console.WriteLine(area == area2);//true

相等比较在我们日常开发中用到地方还是很多的,至于怎么用的更好,我希望这个博客能够帮到自己或者看到这篇博客有收获的人。

 

 

posted @ 2020-04-29 22:31  飞天猪皮怪  阅读(863)  评论(0编辑  收藏  举报