ユーザー定義の値型の場合、コードはコンパイルされません。
具体的には、次のエラーでコンパイルに失敗します:「演算子'=='はタイプ'a'および'a'のオペランドに適用できません」。
「==および!=演算子は、構造体が明示的にオーバーロードしない限り、構造体を操作できません。」
両方をオーバーロードする必要があります。「...構造体の場合、Object.Equals(Object)(System.ValueTypeのオーバーライドされたバージョン)のデフォルトの実装は、次を使用して値の同等性チェックを実行するためEquals()
、メソッドで
デフォルトを使用することはおそらく望ましくありません。タイプ内のすべてのフィールドの値を比較するためのリフレクション。実装者が構造体の仮想Equalsメソッドをオーバーライドする場合、目的は、値の同等性チェックを実行するより効率的な手段を提供し、オプションで、構造体のフィールドまたはプロパティ。」
ユーザー定義の参照型の場合(OPの例のように簡略化された場合):
「==および!=演算子は、クラスがオーバーロードしなくてもクラスで使用できます。ただし、デフォルトの動作では、参照の等価性チェックが実行されます。クラスでは、Equalsメソッドをオーバーロードする場合は、 ==および!=演算子ですが、必須ではありません。」
演算子をオーバーロードしない場合、おそらく参照等価性テストのみが行われます。
演算子のオーバーロード解決により、デフォルトの代わりに別の実装が選択される可能性があるため、「簡略化されたケース」。
//Minimal example, for demonstration only.
//No Equals(), GetHaschode() overload, no IEquatable<T>, null checks, etc..
class Program
{
static void Main()
{
MyMoreDerived a = new MyMoreDerived() { fbase = 1, fderived = 3 };
MyMoreDerived b = new MyMoreDerived() { fbase = 2, fderived = 3 };
//Even though MyMoreDerived does not overload the operators, this
//will succeed - the definition in MyDerived will be used.
if (a == b)
{
//Reached, because the operator in MyDerived is used.
Console.WriteLine("MyDerived operator used: a == b");
}
a.fderived = 2;
b.fbase = 1;
//a => {1, 2}
//b => {1, 3}
//Since 2 != 3, the operator in MyDerived would return false.
//However only the operator in MyBase will be used.
if ((MyBase)a == (MyBase)b)
{
//Reached, because the operator in MyBase is used.
Console.WriteLine("MyBase operator used: a == b");
}
b.fderived = 2;
//a => {1, 2}
//b => {1, 2}
//Now both operator definitions would compare equal,
//however they are not used.
if ((object)a != (object)b)
{
//Reached, because the default implementation is used
//and the references are not equal.
Console.WriteLine("Default operator used: a != b");
}
}
class MyBase
{
public int fbase;
public static bool operator ==(MyBase x, MyBase y)
{
return x.fbase == y.fbase;
}
public static bool operator !=(MyBase x, MyBase y)
{
return x.fbase != y.fbase;
}
}
class MyDerived : MyBase
{
public int fderived;
public static bool operator ==(MyDerived x, MyDerived y)
{
return x.fderived == y.fderived;
}
public static bool operator !=(MyDerived x, MyDerived y)
{
return x.fderived != y.fderived;
}
}
class MyMoreDerived : MyDerived
{
}
}
シングルトンは、参照型のコンテキストで最も意味があり、その目的は1つの特定のインスタンスを返すことです。参照が同じであるが、オブジェクトがそれ自体と「等しくない」という合理的なケースを想像することはできません。
リモーティングを使用する場合でも、運用コントラクトをデータコントラクトから分離することをお勧めします。前者は通常MarshalByRefObject
、サーバー側のsによって実装されます(インターフェイスによって定義された操作を実装します)。後者は、値によってマーシャリングされ、クライアントとサーバーによって共有される可能性のあるデータ/メッセージクラスを使用します。データクラスの演算子をオーバーロードする場合は、大きな問題にはならない可能性があります。ただし、これらはリモートオブジェクトを参照/呼び出すべきではないと私は信じています。
==
オペレーターをオーバーロードするカスタムクライアントプロキシを提供する場合でも、リモート呼び出しとオペレーターを隠すことは非常に悪い習慣であり、デバッグの悪夢!=
です。(私があなたの意図を理解しているなら、それは私にはわかりません。)