C#には2つのオブジェクトがあり、ブール型か他の型かはわかりません。ただし、これらのC#を比較しようとすると、正しい答えが得られません。私はVB.NETで同じコードを試しましたが、それはそれでした!
誰かが解決策がある場合、これを修正する方法を教えてもらえますか?
C#:
object a = true;
object b = true;
object c = false;
if (a == b) c = true;
MessageBox.Show(c.ToString()); //Outputs False !!
VB.NET:
Dim a As Object = True
Dim b As Object = True
Dim c As Object = False
If (a = b) Then c = True
MessageBox.Show(c.ToString()) '// Outputs True
C#では、==
演算子(参照型の式に適用される場合)は、オーバーロードでない限り、reference等価チェックを実行します。ボクシング変換の結果である2つの参照を比較しているため、これらは別個の参照です。
編集:==
をオーバーロードする型を使用すると、異なる動作を得ることができますが、それは式のcompile-time型に基づいています。たとえば、string
は==(string, string
を提供します):
string x = new string("foo".ToCharArray());
string y = new string("foo".ToCharArray());
Console.WriteLine(x == y); // True
Console.WriteLine((object) x == (object) y); // False
ここでは、最初の比較ではオーバーロードされた演算子を使用していますが、2番目の比較では「デフォルト」の参照比較を使用しています。
VBでは、=
演算子はさらに多くの作業を行います。 Option Compare
のようなものがテキストの方法に影響を与える可能性があるため、object.Equals(x, y)
を使用することと同等ではありませんが比較されます。
基本的に、演算子は同じ方法で動作せず、同じ方法で動作することを意図していません。
物事のC#側を説明するJonの答えに加えて、VBの機能は次のとおりです。
In VB with _Option Strict On
_)、_=
_alwaysによる比較は、値の等価性をテストし、参照の等価性はテストしません。実際、_Option Strict On
_は_System.Object
_を定義しないため、_Operator=
_を切り替えるとコードはコンパイルされません。常にalwaysこのオプションをオンにすると、ビーナスフライトラップよりも効果的にバグをキャッチします(ただし、特定のケースでは、このゆるい動作が実際に正しいことを行います)。1
実際、_Option Strict On
_では、VBはC#よりも厳密に動作します。C#では、_a == b
_eitherSomeType.operator==(a, b)
の呼び出しをトリガーします。これが存在しない場合は、参照の等価比較を呼び出します(これはobject.ReferenceEquals(a, b)
の呼び出しと同等です)。
一方、VB=では、比較_a = b
_alwaysは等価演算子を呼び出します。2 参照等価比較を使用する場合は、_a Is b
_(これもObject.ReferenceEquals(a, b)
と同じです)を使用する必要があります。
1) _Option Strict Off
_を使用するのが悪い考えである理由をここに示します。私は、.NETの公式リリースの前から数年前まで、ほぼ10年間VB.NETを使用しており、I '全く考えられない_a = b
_が_Option Strict Off
_で何をするか。ある種の平等比較を行いますが、何が正確に起こり、なぜ、何も考えられません。ただし、C#のdynamic
機能よりも複雑です(十分に文書化されたAPIに依存しているため)。 MSDNの説明:
_
Option Strict On
_は強い型付けを提供し、データ損失を伴う意図しない型変換を防ぎ、遅延バインディングを禁止し、パフォーマンスを向上させるため、その使用を強くお勧めします。
2) ジョンは、1つの例外、文字列について言及しました。この場合、後方互換性の理由から、等価比較はさらに多くのことを行います。
オブジェクトインスタンスは演算子「==」と比較されません。メソッド「等しい」を使用する必要があります。 「==」演算子では、オブジェクトではなく参照を比較しています。
これを試して:
public class MyObject
{
public MyObject(String v)
{
Value = v;
}
public String Value { get; set; }
}
MyObject a = new MyObject("a");
MyObject b = new MyObject("a");
if(a==b){
Debug.WriteLine("a reference is equal to b reference");
}else{
Debug.WriteLine("a reference is not equal to b reference");
}
if (a.Equals(b)) {
Debug.WriteLine("a object is equal to b object");
} else {
Debug.WriteLine("a object is not equal to b object");
}
結果:
a reference is not equal to b reference
a object is not equal to b object
今、これを試してください:
public class MyObject
{
public MyObject(String v)
{
Value = v;
}
public String Value { get; set; }
public bool Equals(MyObject o)
{
return (Value.CompareTo(o.Value)==0);
}
}
MyObject a = new MyObject("a");
MyObject b = new MyObject("a");
if(a==b){
Debug.WriteLine("a reference is equal to b reference");
}else{
Debug.WriteLine("a reference is not equal to b reference");
}
if (a.Equals(b)) {
Debug.WriteLine("a object is equal to b object");
} else {
Debug.WriteLine("a object is not equal to b object");
}
結果:
a reference is not equal to b reference
a object is equal to b object
問題は、C#の==演算子が、2つのパラメーターのコンパイル時間タイプに基づいて、静的メソッドの呼び出しであるということです(まあ、技術的にはそうではないかもしれませんが、そうかもしれません)。 。これらのオブジェクトの実際の実行時のタイプは問題ではありません。
コンパイル時の型に基づいて、コンパイラは使用するoperator ==
の実装を決定します。デフォルトのobject
実装を使用するか、言語が提供する数値オーバーロードの1つを使用するか、ユーザー定義の実装にすることができます。
これは、VBとは異なり、VBはコンパイル時に実装を決定しません。実行時まで待機し、指定された2つのパラメータを検査します使用する==
演算子の実装を決定します。
コードにはブール値が含まれていますが、object
型の変数に含まれています。 変数はobject
型であるため、C#コンパイラは==
のobject
実装を使用します。これはreferencesを比較します、オブジェクトインスタンスではありません。ブール値はボックスであるため、値が同じであっても、同じ参照を持ちません。
VBコードは変数の型を気にしません。実行時まで待機してから2つの変数をチェックし、両方のブール型の実際であることを確認しますブール値の==
演算子実装を使用します。この実装は、参照ではなくブール値の値を比較します(そして、ブール値はその演算子を呼び出す前にボックス化解除されるため、参照比較は意味がありません)ブール値の値が同じであるため、trueを返します。