简体   繁体   中英

C# ValueType equals not comparing properties?

The following prints equals:

struct A
{
    int x;
    public A(int _x) { x = _x; }
    public int Y
    {
        get
        {
            Random r = new Random();
            return r.Next(0, 1000);
        }
    }
}

static void Main(string[] args)
{
    A a1 = new A(1),a2 = new A(1);
    if (a1.Equals(a2))
    {
        Console.Write("Equals");
    }
    else
    {
        Console.Write("Different");
    }
}

Is there anyway to get C# to return false in that case? Meaning, to take the properties under consideration when comparing value types?

Write equal then hit "tab" button twice:

// override object.Equals
        public override bool Equals(object obj)
        {


            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }

            // TODO: write your implementation of Equals() here
            throw new NotImplementedException();
            return base.Equals(obj);
        }

This is an automatically generated snippet. Now you can try something like:

// override object.Equals
        public override bool Equals(object obj)
        {

            // checks for A versus A    
            if (obj == null || GetType() != obj.GetType())
            {
                return false;
            }

            // TODO: write your implementation of Equals() here
            throw new NotImplementedException();
            int compareThis=(A)obj.x;
            return ((A)base).x==compareThis; // maybe casting is not needed
        }

The recommended approach is to use IEquatable<T> instead of using the default inherited Equals method. The IEquatable generic interface defines a generalized method that a value type or class implements to create a type-specific method for determining equality of instances.

  using System;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            A a1 = new A(1), a2 = new A(1);
            //here  the  CLR  will do a lot of unboxing and check operations via reflection in  order to make a comparaison between fields value. 
            //just take a look bellow  at the decompiled default Equals method how it's  done 
            if (a1.Equals(a2))
            {
                Console.Write("Equals");
            }
            else
            {
                Console.Write("Different");
            }
        }
    }

   public  struct A : IEquatable<A>
    {
        int x;
        public A(int _x) { x = _x; }
        public int Y
        {
            get
            {
                Random r = new Random();
                return r.Next(0, 1000);
            }
        }
         //here no boxing or  unboxing is needed  even if is a value  type  and the CLR will call this method first 
        public bool Equals(A other)
        {
            return this.Y == other.Y;   
        }
        public override bool Equals(object obj)
        {
            //this is  why a bad approach to compare both objects  you  need to unbox the struct arguments wich hurting  performance 
            return this.Y == ((A)obj).Y;
        }

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

       //default  implementation 
        //public override bool Equals(object obj)
        //{
        //    return base.Equals(obj);
        //}
    }
}

CLR Implementation

The CLR what's going underneath

 public override bool Equals(object obj)
    {
      if (obj == null)
        return false;
      RuntimeType runtimeType = (RuntimeType) this.GetType();
      if ((RuntimeType) obj.GetType() != runtimeType)
        return false;
      object a = (object) this;
      if (ValueType.CanCompareBits((object) this))
        return ValueType.FastEqualsCheck(a, obj);
      FieldInfo[] fields = runtimeType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
      for (int index = 0; index < fields.Length; ++index)
      {
        object obj1 = ((RtFieldInfo) fields[index]).UnsafeGetValue(a);
        object obj2 = ((RtFieldInfo) fields[index]).UnsafeGetValue(obj);
        if (obj1 == null)
        {
          if (obj2 != null)
            return false;
        }
        else if (!obj1.Equals(obj2))
          return false;
      }
      return true;
    }

This is very similar to this question.
All you need to do is to override the Equals method:

struct A
{
    int x;
    public A(int _x) { x = _x; }
    public int Y
    {
        get
        {
            Random r = new Random();
            return r.Next(0, 1000);
        }
    }


       public override bool Equals(object obj) 
       {
          //compare whatever you want...

       }

    }
}

覆盖equal方法,并根据属性比较返回true或false。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM