• 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

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

     

  • 相关阅读:
    线性回归的从零开始实现
    比赛总结
    计数学习笔记
    DP计数问题
    多项式学习笔记
    数据结构学习笔记
    子集运算学习笔记
    待学习
    ICPC2018焦作 题解
    ICPC2018焦作 H题 Can You Solve the Harder Problem?
  • 原文地址:https://www.cnblogs.com/aqgy12138/p/12805521.html
Copyright © 2020-2023  润新知