642

2つの文字列を比較するSilverlightアプリケーションの条件があります。何らかの理由で、使用する==false.Equals()返され、 trueが返されます。

コードは次のとおりです。

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content.Equals("Energy Attack"))
{
    // Execute code
}

if (((ListBoxItem)lstBaseMenu.SelectedItem).Content == "Energy Attack")
{
    // Execute code
}

これが起こっている理由について何か理由はありますか?

4

19 に答える 19

493

==タイプの式で使用される場合object、それはに解決されSystem.Object.ReferenceEqualsます。

Equalsは単なるvirtualメソッドであり、そのように動作するため、オーバーライドされたバージョンが使用されます(stringタイプの場合はコンテンツを比較します)。

于 2009-05-02T13:39:29.853 に答える
381

オブジェクト参照を文字列と比較する場合(オブジェクト参照が文字列を参照している場合でも)、==文字列クラスに固有の演算子の特別な動作は無視されます。

通常(文字列を処理しない場合、つまり)、Equals比較し、オブジェクト参照を比較します。比較している2つのオブジェクトがオブジェクトの同じ正確なインスタンスを参照している場合、両方がtrueを返しますが、一方が同じコンテンツを持ち、異なるソースからのものである場合(同じデータを持つ別のインスタンスである場合)、Equalsのみがtrueを返します。ただし、コメントに記載されているように、文字列は演算子をオーバーライドするため、オブジェクト参照ではなく文字列参照を純粋に処理する場合、個別のインスタンスであっても値のみが比較されるため、特殊なケースです。次のコードは、動作の微妙な違いを示しています。====

string s1 = "test";
string s2 = "test";
string s3 = "test1".Substring(0, 4);
object s4 = s3;

Console.WriteLine($"{object.ReferenceEquals(s1, s2)} {s1 == s2} {s1.Equals(s2)}");
Console.WriteLine($"{object.ReferenceEquals(s1, s3)} {s1 == s3} {s1.Equals(s3)}");
Console.WriteLine($"{object.ReferenceEquals(s1, s4)} {s1 == s4} {s1.Equals(s4)}");

出力は次のとおりです。

True True True
False True True
False False True
于 2009-05-02T13:40:30.193 に答える
33

== 演算子

  1. オペランドが値型で、それらのが等しい場合、true を返します。それ以外の場合は false を返します。
  2. オペランドが文字列以外の参照型であり、両方が同じインスタンス(同じオブジェクト) を参照している場合、true または false を返します。
  3. オペランドが文字列型で、それらのが等しい場合は true を返し、それ以外の場合は false を返します。

.等しい

  1. オペランドが参照型の場合、参照の等価性が実行されます。つまり、両方が同じインスタンス(同じオブジェクト) を参照している場合、true を返し、それ以外の場合は false を返します。
  2. オペランドが値型の場合、== 演算子とは異なり、最初にをチェックし、型が同じ場合は == 演算子を実行し、それ以外の場合は false を返します。
于 2012-10-11T07:54:23.153 に答える
20

まず、違いあります。数字の場合

> 2 == 2.0
True

> 2.Equals(2.0)
False

そして文字列の場合

> string x = null;
> x == null
True

> x.Equals(null)
NullReferenceException

どちらの場合も、==より便利に動作します.Equals

于 2013-08-15T11:15:44.410 に答える
15

オブジェクトを文字列にキャストすると、正しく機能することを付け加えておきます。これが、コンパイラが次のような警告を表示する理由です。

意図しない参照比較の可能性。値の比較を行うには、左側を「string」型にキャストします

于 2011-08-11T03:35:44.653 に答える
2

答えにもう1点追加します。

.EqualsTo()メソッドは、文化と大文字と小文字を区別して比較するための準備を提供します。

于 2012-07-11T11:04:21.103 に答える
2

ここで少し混乱しています。Content の実行時型が文字列型の場合、== と Equals の両方が true を返す必要があります。ただし、これは当てはまらないため、Content の実行時型は文字列ではなく、その上で Equals を呼び出すと参照等価が行われ、これが Equals("Energy Attack") が失敗する理由を説明しています。ただし、2 番目のケースでは、どのオーバーロードされた == 静的演算子を呼び出すかについての決定はコンパイル時に行われ、この決定は ==(string,string) のように見えます。これは、コンテンツが文字列への暗黙的な変換を提供することを示唆しています。

于 2009-05-02T16:02:44.283 に答える
1

これは、値の等価性 (equal メソッド) と参照の等価性 (== 演算子) によるものです。equal メソッドは値をチェックし、同じ == が参照をチェックするためです。

== https://referencesource.microsoft.com/の文字列クラス内で利用可能なコードをオーバーライドする演算子

これで理解しやすくなりました。 equal メソッドには、文字列クラス自体からの実装とオブジェクト クラスからの実装の 2 つの実装があります。また、いくつかの基本的なコードを実行し、ベンチマークを理解しようとします。

以下の結果を共有しています どこか間違っている場合は、修正またはアドバイスしてください。3 つのケースがあり、すべてのケースで同じコードを実行した結果がこれです。

ケース 1:ここでは文字列を使用しています。2 つの文字列を比較する equal メソッドで、両方の文字列が同じ値を持っています。文字列.equals(a,b)

1 回目:5608195 ティック

2 回目:5529387 ティック

3 回目: 5622569 ティック

合計ティック: 16760151

ケース 2:ここでは文字列を使用しています。2 つの文字列を比較する equal() メソッド (オーバーロードされたもの) で、両方の文字列が同じ値を持っています。a.equals(b)

1 回目: 6738583 ティック

2 回目の実行: 6452927 ティック

3 回目の実行: 7168897 ティック

合計ティック数=20360407

ケース 3:ここでは == 演算子を使用して 2 つの文字列を比較していますが、両方の文字列が同じ値を持っています。a==b

1 回目: 6652151 ティック

2 回目の実行: 7514300 ティック

3 回目の実行: 7634606 ティック

合計ティック数=21801057

class Program
{
    private static int count;
    static string a = "abcdef";
    static string b = "abcdef";
    static void Main(string[] args)
    {            

        for (int j = 1; j <= 3; j++)
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            for (int i = 1; i <= 1000; i++)
            {
                checkString();
            }
            sw.Stop();
            Console.WriteLine(sw.ElapsedTicks);
        }
        Console.ReadLine();

    }
    public static void checkString()
    {
        for (int i = 1; i <= 100000; i++)
        {
            if (a==b)
                count++;
        }
    }
}
于 2021-07-09T13:31:35.750 に答える
0

==C#のトークンは、2 つの異なる等値チェック演算子に使用されます。コンパイラは、そのトークンを検出すると、比較対象の型のいずれかが、比較対象の特定の組み合わせ型 (*)、または両方の型を変換できる型の組み合わせに対して等値演算子のオーバーロードを実装しているかどうかを確認します。コンパイラがそのようなオーバーロードを見つけた場合、それを使用します。それ以外の場合、2 つの型が両方とも参照型であり、それらが無関係なクラスではない場合 (インターフェイスであるか、関連するクラスである可能性があります)、コンパイラは==参照比較演算子と見なします。どちらの条件にも当てはまらない場合、コンパイルは失敗します。

他の一部の言語では、2 つの等値チェック演算子に別々のトークンを使用することに注意してください。たとえば、VB.NET では、=トークンは式内でオーバーロード可能な等値チェック演算子のみにIs使用され、参照テストまたは null テスト演算子として使用されます。=等値チェック演算子をオーバーライドしない型で使用するは失敗し、Is参照の等値または null をテストする以外の目的で使用しようとすると失敗します。

(*) 通常、型はそれ自体との比較のために等値をオーバーロードするだけですが、他の特定の型との比較のために等値演算子をオーバーロードすると便利な場合があります。たとえば、16777217 が 16777216f と等しいと報告しないように、intとの比較のために等値演算子を定義することができました (そして、IMHO は定義する必要がありましたが、定義しませんでした) 。floatそのままでは、そのような演算子が定義されていないため、C# は to をプロモートしintfloat等価チェック演算子が認識する前に 16777216f に丸めます。その演算子は、2 つの等しい浮動小数点数を認識し、行われた丸めを認識せずに、それらを等しいと報告します。

于 2014-02-14T17:47:05.593 に答える
-2

Equal と == の唯一の違いは、オブジェクト タイプの比較にあります。参照型と値型などの他のケースでは、それらはほとんど同じです (両方ともビット単位の等価であるか、両方が参照等価です)。

object: Equals: ビット単位の等価性 ==: 参照の等価性

string: (equals と == は string と同じですが、string の一方を object に変更すると、比較結果が異なります) Equals: ビット単位の等価 == : ビット単位の等価

詳細については、こちらを参照してください。

于 2014-12-30T02:11:37.837 に答える