Для определенных пользователем типов значений ваш код не будет компилироваться.
В частности, компиляция завершится с ошибкой: «Оператор» == не может быть применен к операндам типа «a» и «a» ».
"Операторы == и! = Не могут работать со структурой, если структура явно не перегружает их."
Вы должны перегрузить оба из них . Скорее всего, вы не хотите использовать в своем методе значение по умолчанию Equals()
, так как
"... для структур, реализация по умолчанию Object.Equals (Object) (которая является переопределенной версией в System.ValueType) выполняет проверку равенства значений, используя отражение для сравнения значений каждого поля в типе. Когда реализатор переопределяет виртуальный метод 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
{
}
}
Синглтоны наиболее значимы в контексте ссылочных типов, и их цель - вернуть один конкретный экземпляр. Я не могу представить разумный случай, когда ссылка такая же, но объект не "равен" самому себе.
Даже при удаленном взаимодействии рекомендуется отделять контракты на операции от контрактов на данные.
Первый тип обычно реализуется MarshalByRefObject
s на стороне сервера - реализуя операции, определенные интерфейсами, а второй - с классами данных / сообщений, которые маршалируются по значению и могут совместно использоваться клиентом и сервером. Это не может быть большой проблемой, если вы перегружаете операторы в классах данных. Я считаю, что они не должны ссылаться на удаленные объекты и совершать их.
Даже если вы предоставляете собственный клиентский прокси, который перегружает операторов, это очень плохая практика и кошмар отладки, чтобы скрыть удаленные вызовы за операторами ==
и !=
.
(Если я понимаю ваши намерения, в этом я не уверен.)