2010-12-06 9 views
2

私は理解していません。私のクラスを比較するのはなぜ偽を返すのですか?私は考えました.Equalsは、各要素がお互いにあるかどうかをチェックし、両方のクラスで私がそれぞれ私になるべきです。だから問題は何ですか?そして、これを真にするにはどうしたらいいですか?私の2つのクラスを比較してもfalseが返されるのはなぜですか?

public class MyTest 
{ 
    string me; 
    public MyTest(){} 
    public MyTest(string v) { me = v; } 
    public static implicit operator string(MyTest v){return v.me;} 
    public static implicit operator MyTest(string v) { return new MyTest(v); } 
    public override string ToString(){ return me;} 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     Console.WriteLine("{0}", new MyTest("a").Equals(new MyTest("a"))); 
     Console.WriteLine("{0}", new MyTest("a") == new MyTest("a")); 
     //false, false 

答えて

14

クラスは参照型です。したがって、デフォルトの 'Equals'メソッドと等価演算子は、2つのインスタンスが等しいかどうかを検証するために、インスタンスの '参照'(つまりメモリアドレス)を比較します。

つまり、参照型の等価性によって、2つのインスタンスが同じインスタンスであるかどうかがチェックされます。

この動作は、EqualsメソッドとGetHashCodeメソッドをオーバーライドすることでオーバーライドできます。さらに、等価演算子と等価性演算子をオーバーロードすることができます。

0

参照型の場合、等しいと '=='は、2つのオブジェクトが同じ参照を指すかどうかを調べます。それはクラスの値をチェックしません。クラスのインスタンスと比較する独自のロジックを提供するには、equalsをオーバーライドする(またはIEquatableを実装する)必要があります。

0

object.Equals(およびGetHashCode)をオーバーライドする必要があります。デフォルトの実装をオーバーライドしない場合は、それらが同じオブジェクトであるかどうかを返します(フィールドを比較しません)。

1

あなたはMyTestクラスのEqualsメソッドをオーバーライドし、その方法では、カスタム比較ロジックを実装する必要があります。これがなければ、デフォルト実装は参照のみを比較します。

このリンクを参照してください - デフォルトでは、参照型のために、それは彼らの参照を比較するため、あなたはEqualsメソッドをオーバーライドする必要がGuidelines for Overloading Equals() and Operator == (C# Programming Guide)

6

:Equalsメソッドをオーバーライドするとき

public override bool Equals(object obj) 
{ 
    var other = obj as MyTest; 
    if (other == null) 
    { 
     return false; 
    } 
    return other.me == me; 
} 

はまた、それがすることをお勧めしますGetHashCodeメソッドもオーバーライドします。

public override int GetHashCode() 
{ 
    return (me ?? string.Empty).GetHashCode(); 
} 
0

ehy代わりに構造体を使用しないでください(これは値型であり、実際にオペレータEqualsをオーバーロードしないその部品

public struct MyTest 
{ 
    string me; 
    public MyTest(string v) { me = v; } 
    public static implicit operator string(MyTest v) { return v.me; } 
    public static implicit operator MyTest(string v) { return new MyTest(v); } 
    public override string ToString() { return me; } 
} 
+3

それは構造体は、デフォルトで毎のフィールド平等を行うことは事実ですが、その*それだけで*が本当に構造体不必要なものを作るための正当な理由はない... –

+0

OPとしては、 Stringで暗黙の変換を実行していますが、これは不変です。このシナリオでは、構造体は良いcanidateになる可能性があります。 –

1

あなたのクラスMyTestの比較の合計を経由して比較されます。だから==と同じことをやろうとして、デフォルトでは、あるあなたが

Console.WriteLine("{0}", new MyTest("a").Equals(new MyTest("a"))); 

を呼び出す行に。

あなたは明示的にこのようなあなたのクラスでの平等を定義する必要があります:実際に他の1内部の一つに、このオブジェクト内の文字列を比較します

public override bool Equals(Object obj) 
{ 
    return (MyTest)obj.me == this.me; 
} 

を。 .Equalsを呼び出して==演算子を使用すると、定義された等価が使用されます。

編集:より包括的なソリューションを@Darinディミトロフの回答を参照してください。

1

あなたは2つのクラスを比較するのではなく、2つの異なるクラスのインスタンスを比較しています。 2つの異なる参照を比較しているため、テストはfalseを返します。

EqualsGetHashCodeを上書きして、この動作を無効にすることができます。

-2

私が知る限り、デフォルトでは "=="は2つのオブジェクトが同じかどうかを識別します。と "等しい"はその値を比較します。

+0

これはJavaでも当てはまります。 – mgiuca

1

structは、デフォルトでフィールドを比較します。 classはデフォルトで参照を比較します。あなたは単にそれをstructにして、ボクシングなどを避けるために、GetHashCodeEqualsとにかく(プラス)を上書きする必要があります。既存のコードの場合例えば

public static bool operator ==(MyTest x, MyTest y) { 
    if(x == null && y == null) return true; 
    return x != null && y != null && x.me == y.me; 
} 
public static bool operator !=(MyTest x, MyTest y) { 
    if (x == null && y == null) return false; 
    return x == null || y == null || x.me != y.me; 
} 
public override bool Equals(object obj) { 
    MyTest other = obj as MyTest; 
    return other != null && other.me == me; 
} 
public override int GetHashCode() { 
    return me == null ? 0 : me.GetHashCode(); 
} 
+1

本当ですか? GetHashCode、Equals、およびToStringをオーバーライドしない限り、Structsはボックス化されませんか?それには理由がありますか? – mgiuca

+0

@mgiuca:良いコメントです。 @マルクグラヴェル:私はいつもボクシングの理由は、オブジェクトがクラス(または構造体)を識別するために使用することができるvtableを持っているオブジェクトだと思った。しかし論理的には、あなたが構造体でボクシングを避けることができれば、それは本当ではないでしょう。もう一度私の前提は間違っている* sigh *。 GetHashCodeとToStringがボクシングを避けるのに役立つのはなぜですか? –

+0

@mgiuca @acidzombie - これは 'constrained'オペコードの結果です(http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.constrained.aspx) - 構造体がこれを直接実装するには、仮想オブジェクトを呼び出すためにボックスに入れる必要があります。*メソッド –

関連する問題