Что произойдет, если "== оператор не определен"? - PullRequest
3 голосов
/ 20 марта 2010

Что произойдет, если "== оператор не определен"?

Пример:

class a
{
    int variable = 0;
}
class b
{
    void proc()
    {
        a ref1 = new a();
        a ref2 = new a();
        bool cmp1 = ref1 == ref2;//?
        bool cmp2 = ref1 == ref1;//?
    }
}

Отличается ли он при работе со структурами?

Как насчет маршалированных (System.Runtime.Remoting.*) объектов (синглетонов)?

Ответы [ 4 ]

4 голосов
/ 20 марта 2010

Для определенных пользователем типов значений ваш код не будет компилироваться.

В частности, компиляция завершится с ошибкой: «Оператор» == не может быть применен к операндам типа «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 на стороне сервера - реализуя операции, определенные интерфейсами, а второй - с классами данных / сообщений, которые маршалируются по значению и могут совместно использоваться клиентом и сервером. Это не может быть большой проблемой, если вы перегружаете операторы в классах данных. Я считаю, что они не должны ссылаться на удаленные объекты и совершать их.

Даже если вы предоставляете собственный клиентский прокси, который перегружает операторов, это очень плохая практика и кошмар отладки, чтобы скрыть удаленные вызовы за операторами == и !=. (Если я понимаю ваши намерения, в этом я не уверен.)

1 голос
/ 20 марта 2010

Из MSDN:

Для предопределенных типов значений оператор равенства (==) возвращает true, если значения его операндов равны, в противном случае - false. Для ссылочных типов, отличных от строки, == возвращает true, если два его операнда ссылаются на один и тот же объект. Для типа строки == сравнивает значения строк.

1 голос
/ 20 марта 2010

Когда == не переопределяется, я считаю, что он сравнивает ссылки, проверяя, являются ли они одним и тем же объектом.

Пример:

MyClass a = new MyClass(1);
MyClass b = new MyClass(1);
MyClass c = a;

if (a == b) // false
    ...
if (a == c) // true
    ...

Поэтому в приведенном выше коде cmp1 будет ложным, а cmp2 будет истинным

Однако для определяемых пользователем типов значений сравнивается фактическое значение типа.

1 голос
/ 20 марта 2010

Вероятно, он будет сравнивать указатели 'a' и 'b', указывают ли они на один и тот же объект в памяти.

Если вам нужно сравнить поля этих объектов, вам нужно определить функцию сравнения.

Вам потребуется наследовать от интерфейса IComparable и определить метод CompareTo.

Смотрите здесь: Интерфейс IComparable

...