ホームページ  >  記事  >  バックエンド開発  >  C# の「==」と「Equals」のサンプル コードの簡単な分析

C# の「==」と「Equals」のサンプル コードの簡単な分析

黄舟
黄舟オリジナル
2017-03-09 15:43:551120ブラウズ

ほとんどのネチズンは「==」と「Equals」を次のように要約しています:

  1. 「==」は、2 つの変数の値が等しいかどうかを比較します。

  2. Equals は、2 つの変数が同じオブジェクトを指しているかどうかを比較します。

例: この記事、およびこの記事の例を例として取り上げます。

りー

上記の結論が正しく、「==」が 2 つの変数の値を比較して等しい場合、次のコードは True にはなりません。

public class Person
{
     public Person(string name)
     {
         this.Name = name;
     }

     public string Name { get; set; }
}

 static void Main(string[] args)
 {
     string a = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
     string b = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
     Console.WriteLine(a == b);         //true
     Console.WriteLine(a.Equals(b));    //true

     object g = a;
     object h = b;
     Console.WriteLine(g == h);         //false
     Console.WriteLine(g.Equals(h));    //true

     Person p1 = new Person("jia");
     Person p2 = new Person("jia");
     Console.WriteLine(p1 == p2);       //false
     Console.WriteLine(p1.Equals(p2));  //false
     Person p3 = new Person("jia");
     Person p4 = p3;
     Console.WriteLine(p3 == p4);       //true
     Console.WriteLine(p3.Equals(p4));  //true

     Console.ReadKey();
 }

明らかに、上記の 2 つの文字列変数 a と b は 2 つの異なるオブジェクトを指します。つまり、スタック領域に格納されるメモリ アドレスも異なります。しかし、なぜそれらは等しいのでしょうか?

2. 演算子のオーバーロードとは何ですか?

演算子のオーバーロードとは、既存の演算子を再定義し、異なるデータ型に適応する別の関数を与えることです。簡単な例えをしてみましょう: 「+」演算子、「+」2 つ

すべてのエッジが数値型の変数である場合、「+」演算子は「+」の数学的意味を表します。 「+」演算子のどちらかの側が文字列型の場合、「+」演算子は接続を表します

文字列の意味。このような演算子のオーバーロードの例はたくさんありますが、これはこの記事の主題と何か関係がありますか?私が言いたいのは、上記の文字列変数 a、b は String クラスによるものであるということです

オーバーロードされた演算子「==」。次のソース コードを参照してください:

Console.WriteLine(a == b);         //true

String クラスでは、「==」演算子が実際にオーバーロードされており、「==」だけでなく「!=」もオーバーロードされているのは明らかです。そして、オーバーロードされた演算子メソッド内の String クラスの Equals メソッドを直接呼び出します

ソースコードは次のとおりです:

public static bool operator == (String a, String b)
{
    return String.Equals(a, b);
}
 public static bool operator != (String a, String b)
{
    return !String.Equals(a, b);
}

上記のことから、「==」演算子は、2つの変数に格納された値が等しいかどうかを必ずしも比較するわけではなく、これは現在の演算子が現在の型でオーバーロードされているかどうかに依存すると結論付けることができます。

3. Equals の書き換え

引き続き上記の例:

public static bool Equals(String a, String b)
{
         if ((Object)a==(Object)b)
         {
             return true;
         }

         if ((Object)a==null || (Object)b==null)
         {
             return false;
         }

         if (a.Length != b.Length)
             return false;

         return EqualsHelper(a, b);
 }

上記から、 a と b は 2 つの異なるオブジェクトであることがわかります。しかし、Equals が True の場合、「Equals は 2 つの変数が同じオブジェクトを指しているかどうかを比較する」という上記の結論は無効になります。理由

String クラスの Equals メソッドを見てください:

string a = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
string b = new string(new char[] { 'h', 'e', 'l', 'l', 'o' });
Console.WriteLine(a == b);         //true
Console.WriteLine(a.Equals(b));    //true

上記からわかるように、StringクラスはObjectのEqualsを書き換えるだけでなく、独自のEqualsメソッドを持っていますが、実装コードはほぼ同じです。比較タイプ、メモリアドレス、

最終結果を取得するための実際の値。したがって、Equals は参照アドレスが同じかどうかを 1 つだけ比較する必要はなく、書き換えたりカスタマイズしたりすることもできることは言うまでもありません。でも書き直してください

Equals にも注意が必要です。つまり、HashMap、HashSet、Hashtable を使用する必要がある場合は、GetHashCode() を書き直す必要もあります。

4. 「==」があるときに、なぜ「Equals」が必要なのでしょうか?

中国には「すべての存在には必ず理由と価値がある」ということわざがあります。これは「==」や「Equals」にも当てはまります。参照型における「==」の最も基本的な実装は、比較することです

2 つのオブジェクトのメモリ アドレスが一致しているかどうかを比較し、一致している場合は等しくなります。そうでない場合は等しくありません。このような実装は、明らかにハードウェアの観点から考えられています。2 つのオブジェクトが等しい場合、それらは同じオブジェクトです。 その場合、メモリ内のそれらのアドレスは等しい必要があります。

しかし多くの場合、「行動(方法)」は私たちが世界を観察する視点に依存します。

例: String 型の場合、文字を宣言します 文字列は、

を持っている限り、2 つのオブジェクトがメモリ内で 1 回作成されたか 2 回作成されたか (つまり、メモリ アドレスが等しいかどうか) ではなく、文字列の実際の値を重視します。 実際の値が等しい場合、それらは等しいと見なされます。これは、機械の観点からではなく、ビジネス ロジックから理解されます。もちろん、同じ文字列が上で宣言されています

変数が 1 回作成されるか 2 回作成されるかに関係なく、「定数プール (または文字列保持プール)」が最良の解決策を提供すると思います。

5.「==」と「Equals」の関係は何ですか?

「==」演算子とEqualsは実は補完的なものです。

理由: 「==」演算子の主な実装形式は、「コンピューターの観点 (またはハードウェアの観点)」から実装されています。 Equals は、一般的なビジネス シナリオまたは特定のビジネス シナリオに基づいて実装されます。この 2 つに必然的な関連性はありません。お客様は、独自のビジネス ニーズに応じて異なる方法を選択するだけです。 つまり、Equals in Object は Visual であり、多くのクラスで書き直され、現在の型で必要な特定の動作、つまりポリモーフィズムを実現します。したがって、上記のことを説明するのは難しくありません:

public override bool Equals(Object obj) <br>       {
    if (this == null)                        //this is necessary to guard against reverse-pinvokes and
        throw new NullReferenceException();  //other callers who do not use the callvirt instruction

    String str = obj as String;
    if (str == null)
        return false;

    if (Object.ReferenceEquals(this, obj))
        return true;

    if (this.Length != str.Length)
        return false;

    return EqualsHelper(this, str);
}

public bool Equals(String value) <br>       {
    if (this == null)                        //this is necessary to guard against reverse-pinvokes and
        throw new NullReferenceException();  //other callers who do not use the callvirt instruction

    if (value == null)
        return false;

    if (Object.ReferenceEquals(this, value))
        return true;

    if (this.Length != value.Length)
        return false;

    return EqualsHelper(this, value);
}

オーバーロードされた演算子「==」は Object に実装されていないため、「==」の現在の比較方法は、2 つの変数のスタック空間に格納されているメモリ アドレスが同じかどうかを比較することです。そして等しいというのは

String クラスで Equals を呼び出すと、その理由は、操作中に g 変数が実際に文字列オブジェクトを指し、現在の Object 型が Visual Studio とコンパイラの動作にすぎないためです。つまり、依然として多態性です。

結局のところ、すべてにはルールがあります。「==」と「Equals」も例外ではありません。詳細については、「MSDN に移動」をクリックしてください。


以上がC# の「==」と「Equals」のサンプル コードの簡単な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。