7

特に参照型のコンテンツの等価性について少し混乱しています。どちらの場合も、平等をオーバーライドしていません。では、なぜ動作が異なるのでしょうか。

2 つの簡単なコード例を参照してください。

例 1: True を返します

class Program
{
    static void Main(string[] args)
    {
        object o1 = "ABC";
        object o2 = "ABC";

        Console.WriteLine("object1 and object2: {0}", o1.Equals(o2));
    }
}

例 2: 両方のステートメントが False を返す

class Program
{
    static void Main(string[] args)
    {
        Person person1 = new Person("John");
        Person person2 = new Person("John");

        Console.WriteLine("person1 and person2: {0}", person1.Equals(person2));
        Console.WriteLine("person1 and person2: {0}", ((object)person1).Equals((object)person2));

        Console.ReadLine();
    }
}

public class Person
{
    private string personName;

    public Person(string name)
    {
        this.personName = name;
    }
}
4

7 に答える 7

8

ここでは、2 つの効果が働いています。

  • 文字列のインターンとは、実際には参照の等価性チェックを実行しても、 が表示されることを意味しますTrue。次のように修正できます。

    object o1 = new StringBuilder("ABC").ToString();
    object o2 = new StringBuilder("ABC").ToString();
    
  • System.String Equals文字列の内容を比較するメソッドオーバーライドします。

    このメソッドは、序数 (大文字と小文字を区別し、カルチャを区別しない) 比較を実行します。

    ここで違いを見ることができます:

    object o1 = new StringBuilder("ABC").ToString();
    object o2 = new StringBuilder("ABC").ToString();
    Console.WriteLine(o1.Equals(o2)); // Prints True due to overriding
    Console.WriteLine(ReferenceEquals(o1, o2)); // Prints False
    

あなたのクラスは をオーバーライドしないので、 でデフォルトの実装をEquals取得しています。これは、参照を比較するためのものです。Object

現在のインスタンスが参照型の場合、Equals(Object) メソッドは参照の等価性をテストし、Equals(Object) メソッドの呼び出しは ReferenceEquals メソッドの呼び出しと同等です。

をオーバーライドすることで、かなり簡単に修正できますEquals

// It's easier to implement equality correctly on sealed classes
public sealed class Person
{
    private readonly string personName;

    public Person(string name)
    {
        if (name == null)
        {
            throw new ArgumentNullException("name");
        }
        this.personName = name;
    }

    public override bool Equals(object other)
    {
        Person person = other as Person;
        return person != null && person.personName.Equals(personName);
    }

    // Must override GetHashCode at the same time...
    public override int GetHashCode()
    {
        // Just delegate to the name here - it's the only thing we're
        // using in the equality check
        return personName.GetHashCode();
    }
}

Equals実装では、次を使用できたことに注意してください。

return person != null && person.personName == personName;

...演算子string オーバーロードするためです。==しかし、それは別の問題です:)

于 2013-08-14T16:12:09.467 に答える
3

例 1 は を返します。オブジェクトが文字列として扱われるため、 は値を比較しますtrueEquals例 2 では、オブジェクトのインスタンスを比較していますが、それぞれが異なるメモリ部分を指しているため、それらは等しくありません。

于 2013-08-14T16:10:01.913 に答える
2

デフォルトでは、参照はEqualsデフォルトReferenceEqualsで参照型に設定されます。のインスタンスが必要なPersonので、 を返しますfalse

StringオーバーライドEqualsして値のセマンティクスを実現します。したがって、それstringを使用して同じ値を持つ の2 つの個別のインスタンスを比較すると、 Equalstrue が返されます。

文字列インターンのおかげで、両方"ABC"がまったく同じインスタンスを指しています。したがって、最初の例でもReferenceEquals返されます。true

Equals仮想メソッドであるため、コンパイル時の型は重要ではありません。したがって、キャストobjectは効果がありません。オブジェクトへのキャストのみが影響==!=、それらはオーバーロードされているため、オーバーライドされません。

于 2013-08-14T16:11:50.653 に答える
0

StringはそのメソッドをオーバーライドしEqualsて、2 つの文字列にまったく同じ文字が同じ順序で含まれている場合、Equal. あなたPersonにはそのようなオーバーライドがないため、参照 equals を使用するオブジェクトから継承して、等価のアービターになります。

于 2013-08-14T16:12:44.330 に答える
0

.net でインターンしている文字列のため、文字列参照は同じです (Google で調べてください)。

于 2013-08-14T16:12:52.070 に答える