C# 一貫性のない比較



翻訳者から:

これは、以前はC#開発者の1人であったEric Lippertのブログ 投稿の無料翻訳です。 記録は「質問と回答」の形式です。質問をスキップして回答に進みます。元の質問に慣れることができますが、特に興味深いものはありません。



ただし、まずは次のコードをご覧ください。Googleとコンパイルを行わずに、比較の9つのケースで何が起こるかを調べ、回答を確認してください(アンケートの場合)。

int myInt = 1; short myShort = 1; object objInt1 = myInt; object objInt2 = myInt; object objShort = myShort; Console.WriteLine(myInt == myShort); // scenario 1 Console.WriteLine(myShort == myInt); // scenario 2 Console.WriteLine(myInt.Equals(myShort)); // scenario 3 Console.WriteLine(myShort.Equals(myInt)); // scenario 4 Console.WriteLine(objInt1 == objInt1); // scenario 5 Console.WriteLine(objInt1 == objShort); // scenario 6 Console.WriteLine(objInt1 == objInt2); // scenario 7 Console.WriteLine(Equals(objInt1, objInt2)); // scenario 8 Console.WriteLine(Equals(objInt1, objShort)); // scenario 9
      
      









C#言語は、開発者が期待するとおりに動作するように設計されています。つまり、 明らかなテクニックと正しいテクニックがまったく同じ言語です。 そして大部分はそうです。 残念ながら、比較はトラップのある言語の一部です。



次のコードを作成して、さまざまな程度の比較を示します。

答え
 int myInt = 1; short myShort = 1; object objInt1 = myInt; object objInt2 = myInt; object objShort = myShort; Console.WriteLine(myInt == myShort); // scenario 1 true Console.WriteLine(myShort == myInt); // scenario 2 true Console.WriteLine(myInt.Equals(myShort)); // scenario 3 true Console.WriteLine(myShort.Equals(myInt)); // scenario 4 false! Console.WriteLine(objInt1 == objInt1); // scenario 5 true Console.WriteLine(objInt1 == objShort); // scenario 6 false!! Console.WriteLine(objInt1 == objInt2); // scenario 7 false!!! Console.WriteLine(Equals(objInt1, objInt2)); // scenario 8 true Console.WriteLine(Equals(objInt1, objShort)); // scenario 9 false!?!
      
      







一体何? 順番に見てみましょう。



最初のケースと2番目のケースでは、 最初に ==



演算子の意味を決定する必要があります。 C#には、さまざまな型を比較す​​るための十数個の組み込み==



演算子があります。

 object == object string == string int == int uint == uint long == long ulong == ulong ...
      
      





int == short



またはshort == int



演算子がないため、最適な演算子を選択する必要があります。 私たちの場合、これはint == int



ステートメントです。 したがって、 short



int



変換され、2つの変数が値で比較されます。 したがって、それらは同等です。



3番目の場合、オーバーロードされたEqualsメソッドのどれを呼び出すかを最初に決定する必要があります。 呼び出し元のインスタンスはint



型であり、3つのEquals



メソッドを実装しています。

 Equals(object, object) //     object Equals(object) //     object Equals(int) //    IEquatable<int>.Equals(int)
      
      





前者は、それを呼び出すのに十分な引数がないため、私たちには適していません。 他の2つのメソッドの中で、パラメーターとしてint



を受け入れるメソッドの方が適しています;常にshort



型の引数をobject



に変換するよりもint



に変換する方が適切です。 したがって、値による比較を使用してint



型の2つの変数を比較するEquals(int)



が呼び出されるため、この式はtrueです。



4番目のケースでは、どのEquals



メソッドが呼び出されるかを再度決定する必要があります。 呼び出し元のインスタンスの型はshort



、これには3つのEquals



メソッドがあります。

 Equals(object, object) //     object Equals(object) //     object Equals(short) //    IEquatable<short>.Equals(short)
      
      





最初のメソッドと3番目のメソッドは、引数が少なすぎるため、適切ではありません。また、 int



型のshort



への暗黙的なキャストがないため、3番目のメソッドは選択されません。 short.Equals(object)



メソッドが残り、その実装は次のコードと同じです。

 bool Equals(object z) { return z is short && (short)z == this; }
      
      





つまり、このメソッドがtrue



を返すためには、 パッケージ化された要素はshort



型である必要があり、展開後はEquals



を呼び出したインスタンスと等しくなければなりません。 ただし、渡された引数はint



であるため、メソッドはfalse



を返しfalse







5番目6番目7番目では、 object == object



比較フォームが選択されます。これは、 Object.ReferenceEquals



メソッドを呼び出すのとObject.ReferenceEquals



です。 明らかに、2つのリンクは5番目のケースでは等しく、 6番目7 番目のケースでは等しくありません。 タイプobject



変数に含まれる値object



重要でobject



ません。値による比較はまったく使用されず、リンクのみが比較されるためです。



8番目9番目のケースでは、静的メソッドObject.Equals



が使用され、次のように実装されます。

 public static bool Equals(object x, object y) { if (ReferenceEquals(x, y)) return true; if (ReferenceEquals(x, null)) return false; if (ReferenceEquals(y, null)) return false; return x.Equals(y); }
      
      





8番目のケースでは、 null



と等しくない2つのリンクがあるため、 int.Equals(object)



が呼び出されます。これは、 short.Equals(object)



メソッドのコードを見ればわかるように、次のように実装されます。

 bool Equals(object z) { return z is int && (int)z == this; }
      
      





引数はint



型のパック変数であるため、値によって比較が行われ、メソッドはtrue



を返しtrue



9番目のケースでは、パック変数の型はshort



であるため、型のチェック( z is int



)は失敗し、メソッドはfalse



を返しfalse







結果

2つの変数を比較するための9つの異なる方法を示しましたが、すべての場合において、比較される変数は1に等しく、半分の場合にのみ比較がtrue



返しtrue



。 これがおかしくて、すべてが混乱していると思うなら、あなたは正しいです! C#での比較は非常に潜行的です。



All Articles