2

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?

Shmoopy
  • 5,334
  • 4
  • 36
  • 72
  • 2
    You can override `Equals` method and do whatever you want in there. – MarcinJuraszek Feb 23 '14 at 08:56
  • 5
    Note that such an `Equals` implementation would break the reflexive part of the contract of `Equals`, as `x.Equals(x)` would usually return `false`. Why on earth would you *want* such bizarre behaviour? – Jon Skeet Feb 23 '14 at 08:57

4 Answers4

3

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
        }
huseyin tugrul buyukisik
  • 11,469
  • 4
  • 45
  • 97
1

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;
    }
BRAHIM Kamel
  • 13,492
  • 1
  • 36
  • 47
  • 2
    It's a really bad idea to make `Equals(T)` give a different result to `Equals(object)`. You should really override both together, and `GetHashCode` at the same time. Yes, it's a good idea to implement `IEquatable`, but that doesn't mean it should give different results to the general `Equals` method. – Jon Skeet Feb 23 '14 at 09:03
  • 1
    I agree just give me the time to complete my answer but you agree using IEquatable is the recommended approach here – BRAHIM Kamel Feb 23 '14 at 09:06
  • I agree that it's a good idea to implement `IEquatable`. I disagree with your initial sentence: "Don't use the default object inherited Equals method." That should be overridden as well. – Jon Skeet Feb 23 '14 at 09:17
  • @JonSkeet now the answer looks better or no ? – BRAHIM Kamel Feb 23 '14 at 11:30
  • It's a bit better, but you're still saying "instead of" rather than "as well as" - and your override will throw an exception if it is passed a reference of the wrong type, when it should just return false. – Jon Skeet Feb 23 '14 at 11:38
  • By instead of I means that the CLR when make a call to Equals it will give precedence to the generic's one – BRAHIM Kamel Feb 23 '14 at 11:55
  • 1
    It's not the CLR choosing that overload - it's the C# compiler. That's a compile-time decision based on the compile-time types of the operands. And your override of Equals is still broken... As is your override of GetHashCode. (Fundamentally you can't implement it properly, because the requirement in the question violates the contract of Equals/GetHashCode, which IMO would be a more useful thing to talk about than `IEquatable`.) – Jon Skeet Feb 23 '14 at 12:00
  • I know that's my override is still broken as he may throw a NullReferenceException but my goal is to illustrate a better approach – BRAHIM Kamel Feb 23 '14 at 12:13
  • Not just that, but a ClassCastException if someone calls foo.Equals ("abc") for example. – Jon Skeet Feb 23 '14 at 12:14
0

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...

       }

    }
}
Community
  • 1
  • 1
Avi Turner
  • 10,234
  • 7
  • 48
  • 75
0

Override equal method and return true or false based on property comparison.

Priyang
  • 376
  • 2
  • 7