2014-02-23 43 views
2

下打印等於:C#ValueType等於不比較屬性?

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"); 
    } 
} 

反正是有得到C#在這種情況下,返回false?意思是,比較值類型時要考慮屬性?

+1

你可以重載'Equals'方法並在那裏做任何你想做的事情。 – MarcinJuraszek

+4

請注意,這樣的'Equals'實現會打破'Equals'合約的反射部分,因爲'x.Equals(x)'通常會返回'false'。爲什麼地球上你會想要這種奇怪的行爲? –

回答

3

寫等於然後打「標籤」按鈕兩次:

// 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); 
     } 

這是一個自動生成的代碼段。現在,你可以嘗試這樣的:

// 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 
     } 
+0

這將不起作用,因爲您正在比較值類型 –

+1

@ K.B:爲什麼這意味着它不起作用? –

+0

如果您僅覆蓋A類,則僅針對A覆蓋它,因此不會爲其他類破壞任何東西嗎? –

1

建議的方法是使用IEquatable<T>而不是使用默認的繼承Equals方法。 IEquatable通用接口定義了值類型或類實現的通用方法,以創建用於確定實例相等性的類型特定方法。

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實現

的CLR是怎麼回事下面

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; 
    } 
+2

讓Equals(T)給「Equals(object)」一個不同的結果是一個非常糟糕的主意。你應該同時覆蓋它們和'GetHashCode'。是的,實現'IEquatable '是一個好主意,但這並不意味着它應該給普通的'Equals'方法帶來不同的結果。 –

+1

我同意給我的時間來完成我的答案,但你同意使用IEquatable 是這裏推薦的方法 –

+0

我同意這是一個好主意,實施'IEquatable '。我不同意你的第一句話:「不要使用默認對象繼承的Equals方法。」這也應該被覆蓋。 –

0

這是非常相似的this問題。
所有你需要做的是重寫Equals方法:

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

     } 

    } 
} 
0

覆蓋等方法,並返回true或false基於性能的比較。