web-dev-qa-db-ja.com

なぜString.Equals over ==を使うのですか?

私は最近大規模なコードベースを紹介され、すべての文字列比較が==の代わりにString.Equals()を使って行われることに気付きました。

その理由は何ですか、あなたは思いますか?

288

開発者ベースの大部分は、文字列を比較するための==の使用が間違っていて機能しないというJavaの背景に由来する可能性があります。

C#では、文字列として型付けされている限り、(実用的な)違いはありません(文字列について)。

それらがobjectまたはTとして型付けされている場合は、ここで他の回答を参照してください。ここで他の回答を参照してください。

297

string.Equals==の間には実用的な違いがあります

bool result = false;

object obj = "String";    
string str2 = "String";
string str3 = typeof(string).Name;
string str4 = "String";
object obj2 = str3;

// Comparision between object obj and string str2 -- Com 1
result = string.Equals(obj, str2);// true
result = String.ReferenceEquals(obj, str2); // true
result = (obj == str2);// true

// Comparision between object obj and string str3 -- Com 2
result = string.Equals(obj, str3);// true
result = String.ReferenceEquals(obj, str3); // false
result = (obj == str3);// false

// Comparision between object obj and string str4 -- Com 3
result = string.Equals(obj, str4);// true
result = String.ReferenceEquals(obj, str4); // true
result = (obj == str4);// true

// Comparision between string str2 and string str3 -- Com 4
result = string.Equals(str2, str3);// true
result = String.ReferenceEquals(str2, str3); // false
result = (str2 == str3);// true

// Comparision between string str2 and string str4 -- Com 5
result = string.Equals(str2, str4);// true
result = String.ReferenceEquals(str2, str4); // true
result = (str2 == str4);// true

// Comparision between string str3 and string str4 -- Com 6
result = string.Equals(str3, str4);// true
result = String.ReferenceEquals(str3, str4); // false
result = (str3 == str4);// true

// Comparision between object obj and object obj2 -- Com 7
result = String.Equals(obj, obj2);// true
result = String.ReferenceEquals(obj, obj2); // false
result = (obj == obj2);// false

ウォッチを追加する

obj     "String" {1#}   object {string}
str2    "String" {1#}   string
str3    "String" {5#}   string
str4    "String" {1#}   string
obj2    "String" {5#}   object {string}

それでは{1#}{5#}を見てください。

objstr2str4、およびobj2参照は同じです。

objobj2object typeで、その他はstring typeです。

結論

  1. com1:result =(obj == str2); // true
    • objectstringを比較して、参照等価検査を実行します。
    • objとstr2は同じ参照を指しているので、結果は真です。
  2. com2:result =(obj == str3); // false
    • objectstringを比較して、参照等価検査を実行します。
    • objとstr3は異なる参照を指しているため、結果はfalseです。
  3. com3:result =(obj == str4); // true
    • objectstringを比較して、参照等価検査を実行します。
    • objとstr4は同じ参照を指しているので、結果は真です。
  4. com4:result =(str2 == str3); // true
    • stringstringを比較して、文字列値のチェックを行います。
    • str2とstr3はどちらも "String"なので、結果は真です。
  5. com5:result =(str2 == str4); // true
    • stringstringを比較して、文字列値のチェックを行います。
    • str2とstr4はどちらも "String"なので、結果は真です。
  6. com6:result =(str3 == str4); // true
    • stringstringを比較して、文字列値のチェックを行います。
    • str3とstr4はどちらも "String"なので、結果は真です。
  7. com7:result =(obj == obj2); // false - objectobjectを比較します。異なる参照なので結果はfalse
90
vikas

==とString.Equalsメソッドの間に微妙ですが非常に重要な違いがあります。

class Program
{
    static void Main(string[] args)
    {
        CheckEquality("a", "a");
        Console.WriteLine("----------");
        CheckEquality("a", "ba".Substring(1));
    }

    static void CheckEquality<T>(T value1, T value2) where T : class
    {
        Console.WriteLine("value1: {0}", value1);
        Console.WriteLine("value2: {0}", value2);

        Console.WriteLine("value1 == value2:      {0}", value1 == value2);
        Console.WriteLine("value1.Equals(value2): {0}", value1.Equals(value2));

        if (typeof(T).IsEquivalentTo(typeof(string)))
        {
            string string1 = (string)(object)value1;
            string string2 = (string)(object)value2;
            Console.WriteLine("string1 == string2:    {0}", string1 == string2);
        }
    }
}

この出力を生成します:

value1: a
value2: a
value1 == value2:      True
value1.Equals(value2): True
string1 == string2:    True
----------
value1: a
value2: a
value1 == value2:      False
value1.Equals(value2): True
string1 == string2:    True

==演算子が2つの明らかに等しい文字列にfalseを返していることがわかります。どうして?汎用メソッドで使用されている==演算子はSystem.Objectで定義されているop_equalメソッド(コンパイル時にTが保証されている唯一の保証)であると解決されるため、値等価ではなく参照等価です。

System.Stringとして明示的に型指定された2つの値がある場合、==はSystem.Object.op_equalではなくSystem.String.op_equalに解決されるため、==の値は等価になります。

安全のために、私はほとんど常にString.Equalsを使用しています。その代わりに、必要な値等価性セマンティクスを常に取得しています。

値の1つがnullの場合にNullReferenceExceptionsを避けるために、私は常にstatic String.Equalsメソッドを使用します。

bool true = String.Equals("a", "ba".Substring(1));
64
Andrew Arnott

String.Equalsは、大文字小文字の区別と文化を意識した比較を処理するためのオーバーロードを提供します。あなたのコードがこれらを利用しないのであれば、開発者は単にJavaに慣れているかもしれません、そこで(Matthewが言っているように)、内容の比較をするために.Equalsメソッドを使わなければなりません。

37

どちらの方法も機能的に同じします - 値を比較します。
MSDNに書かれているように:

  • String.Equalsメソッドについて - このインスタンスと指定された別のStringオブジェクトが同じ値を持つかどうかを判断します。 ( http://msdn.Microsoft.com/en-us/library/858x0yyx.aspx
  • ==について - stringは参照型ですが、等価演算子(==!=)は参照ではなく文字列オブジェクトの値を比較するために定義されています。これにより、文字列の等価性のテストがより直感的になります。 ( http://msdn.Microsoft.com/en-en/library/362314fe.aspx

しかし、文字列インスタンスの1つがnullの場合、これらのメソッドは異なる動作をします。

string x = null;
string y = "qq";
if (x == y) // returns false
    MessageBox.Show("true");
else
    MessageBox.Show("false");

if (x.Equals(y)) // returns System.NullReferenceException: Object reference not set to an instance of an object. - because x is null !!!
    MessageBox.Show("true");
else
    MessageBox.Show("false");
20
thezar

Jon Skeetからのいくつかの引用とともに、 この記事 に興味深い記事があります。使い方はほぼ同じです。

Jon Skeet氏は、インスタンスEqualsのパフォーマンスは「文字列が短い場合はわずかに優れています。文字列の長さが増すにつれて、その差はまったく意味がなくなります」と述べています。

16

さらに違いがあることを付け加えたいと思います。それはAndrewが投稿したものと関係があります。

それはまた私達のソフトウェアのバグを見つけることが非常に迷惑なことに関連しています。次の簡単な例を参照してください(私もnullチェックを省略しました)。

public const int SPECIAL_NUMBER = 213;

public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
{
    return numberTextBoxTextValue.Equals(SPECIAL_NUMBER)
}

これはコンパイルされ、常にfalseを返します。以下はコンパイルエラーになりますが:

public const int SPECIAL_NUMBER = 213;

public bool IsSpecialNumberEntered(string numberTextBoxTextValue)
{
    return (numberTextBoxTextValue == SPECIAL_NUMBER);
}

誰かがEqualsを使って異なる型のenumを比較するという同様の問題を解決しなければなりませんでした。それがバグの原因であることに気づく前に、このたくさんの時間を読み返すつもりです。特にSPECIAL_NUMBERの定義が問題領域の近くにない場合。

これが私が本当に必要でない状況でEqualsの使用に本当に反対である理由です。あなたは少し型安全性を失います。

5

このページを読み、実際には意味のある違いはないと結論を下したので、バグを解決しようとしている壁に頭をぶつけているところです。 ==から外れて等しい。

Object ==等価は失敗しますが、.Equalsは成功します。これは意味がありますか?

string a = "x";
string b = new String(new []{'x'});

Console.WriteLine("x == x " + (a == b));//True
Console.WriteLine("object x == x " + ((object)a == (object)b));//False
Console.WriteLine("x equals x " + (a.Equals(b)));//True
Console.WriteLine("object x equals x " + (((object)a).Equals((object)b)));//True
4
Andrew