Сравнение + замкнутая иерархия классов ???
От: Аноним  
Дата: 31.07.10 15:36
Оценка:
Здесь
Автор: _FRED_
Дата: 30.07.10
_FRED_ говорит довольно занятную для меня вещь, а именно:

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

Если кому не сложно, не могли-бы вы как-то получше объяснить, пример привести, почему такое возможно Потому что мне кажется, что я не до конца понимаю смысл сказанного.
Re: Сравнение + замкнутая иерархия классов ???
От: TK Лес кывт.рф
Дата: 31.07.10 18:33
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Если кому не сложно, не могли-бы вы как-то получше объяснить, пример привести, почему такое возможно Потому что мне кажется, что я не до конца понимаю смысл сказанного.


    class A
    {
        public override bool Equals(object obj)
        {
            return obj is A;
        }
    }

    class B : A
    {
        public override bool Equals(object obj)
        {
            return obj is B;
        }
    }


a.Equals(b) == true, но b.Equals(a) != true. Обычно в математике операция сравнения является коммутативной — наследование может легко эту коммутативность нарушить.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[2]: Сравнение + замкнутая иерархия классов ???
От: samius Япония http://sams-tricks.blogspot.com
Дата: 31.07.10 19:19
Оценка:
Здравствуйте, TK, Вы писали:

TK>a.Equals(b) == true, но b.Equals(a) != true. Обычно в математике операция сравнения является коммутативной — наследование может легко эту коммутативность нарушить.


Наследование может легко нарушить также рефлексивность, транзитивность и вообще все что можно вообразить.

Однако (это ответ топикстартеру, а не TK), можно от наследников потребовать соблюдения некого контракта. Допустим,этот контракт может быть оформлен в форме тестов, либо фразой в документации вроде "кто не постарался соблюсти контракт, тот ССЗБ".
В контракте можно потребовать не нарушать всяческие хорошие свойства отношений типа коммутативности, рефлексивности, тразнитивности.

В свою очередь, базовые классы должны обеспечить возможность наследникам не нарушать эти свойства. Допустим, есть B:A. B знает как себя сравнивать с A, но он не знает класс Z, соответственно не умеет себя сравнивать с ним. Но Z написан третьими лицами, потому он знает B и знает как себя сравнить с ним. Здесь и далее (а так же у TK) речь идет о сравнении на равенство, а не о сравнении порядка и частичного порядка (>= <=, аки CompareTo), хотя идеи можно продолжить и на CompareTo. Так вот, во имя коммутативности сравнения следует обеспечить возможность сравения B с Z, и обеспечения такого же результата, как и при сравнении Z с B.

Решить это можно следующим образом:
* Класс, например B, сравнивает себя с пришедшим классом в параметре, если знает как, иначе вызывает base.Equals(obj);
* Базовый класс, например A, если видит что !(obj is A) (т.е. не знает, как себя сравнить с obj), то вызывает obj.Equals(this).

Эта идея взята из методов Assign/AssignTo из Delphi.

При должном соблюдении контрактов во всей иерархии наследования, можно обеспечить сохранение всех необходимых свойств проверки на равенство. Но это не значит, что все будет круто автоматически, если соблюдать все правила. Допустим, классы X и Y разрабатываются разными разработчиками. Так вот, кому-то из них придется внести знание о другом классе в свой класс, иначе классы X и Y окажутся несравнимыми.

И опять я настаиваю на том чтобы не задействовать метод Object.Equals(Object). Пусть это будет хотя бы A.Equals(A), чтобы не нарушать логику работы стандартных контейнеров. При необходимости учитывания контейнерами специальной логики сравнения лучше всего скормить контейнеру специальный компарер, настроенный на эту логику.
Re[3]: Сравнение + замкнутая иерархия классов ???
От: samius Япония http://sams-tricks.blogspot.com
Дата: 31.07.10 19:25
Оценка:
Здравствуйте, samius, Вы писали:

S>Решить это можно следующим образом:

S>* Класс, например B, сравнивает себя с пришедшим классом в параметре, если знает как, иначе вызывает base.Equals(obj);
S>* Базовый класс, например A, если видит что !(obj is A) (т.е. не знает, как себя сравнить с obj), то вызывает obj.Equals(this).

Забыл упомянуть, что такая логика должна опираться на знание конкретных типов. Т.е. реализация класса сравнения класса A может сравнивать себя лишь в том случае, если this.GetType() == typeof(A) и obj.GetType == typeof(A). Класс X : A не может ответить равен ли он чему-то, если его тип не X или тип операнда не равен известным ему заблаговременно.
Re[2]: Сравнение + замкнутая иерархия классов ???
От: SpaceConscience  
Дата: 31.07.10 19:39
Оценка: :)
TK>
TK>    class A
TK>    {
TK>        public override bool Equals(object obj)
TK>        {
TK>            return obj is A;
TK>        }
TK>    }

TK>    class B : A
TK>    {
TK>        public override bool Equals(object obj)
TK>        {
TK>            return obj is B;
TK>        }
TK>    }
TK>


TK>a.Equals(b) == true, но b.Equals(a) != true. Обычно в математике операция сравнения является коммутативной — наследование может легко эту коммутативность нарушить.


Это, извини, чепуха. Здесь нарушается LSP, и всего делов. Не нарушай LSP, и будет тебе коммутативность.
Собрался ставить минус? Да сам иди в жопу!

































































.
Re[3]: Сравнение + замкнутая иерархия классов ???
От: samius Япония http://sams-tricks.blogspot.com
Дата: 31.07.10 20:52
Оценка:
Здравствуйте, SpaceConscience, Вы писали:

TK>>
TK>>    class A
TK>>    {
TK>>        public override bool Equals(object obj)
TK>>        {
TK>>            return obj is A;
TK>>        }
TK>>    }

TK>>    class B : A
TK>>    {
TK>>        public override bool Equals(object obj)
TK>>        {
TK>>            return obj is B;
TK>>        }
TK>>    }
TK>>


TK>>a.Equals(b) == true, но b.Equals(a) != true. Обычно в математике операция сравнения является коммутативной — наследование может легко эту коммутативность нарушить.


SC>Это, извини, чепуха. Здесь нарушается LSP, и всего делов. Не нарушай LSP, и будет тебе коммутативность.


    class A
    {
        public override bool Equals(object obj)
        {
            return obj is A;
        }
    }

    class B //: A
    {
        public override bool Equals(object obj)
        {
            return obj is A;// B;
        }
    }

Извини, LSP по отношению к классу A не нарушена, а коммутативности нет.
Re[4]: Сравнение + замкнутая иерархия классов ???
От: SpaceConscience  
Дата: 31.07.10 21:11
Оценка:
S>
S>    class A
S>    {
S>        public override bool Equals(object obj)
S>        {
S>            return obj is A;
S>        }
S>    }

S>    class B //: A
S>    {
S>        public override bool Equals(object obj)
S>        {
S>            return obj is A;// B;
S>        }
S>    }
S>

S>Извини, LSP по отношению к классу A не нарушена, а коммутативности нет.

У тебя отличное чувство юмора. Это прикол такой? Ты привел два никак не связанных класса, для которых LSP не имеет смысла, и оператор Equals при сравнении двух разнотипных объектов тоже не имеет смысла. А с какого рожна здесь должна быть коммутативность-то? Оператор сравнения коммутативен потому, что он утверждает равенство двух объектов, а здесь оператор сравнения не пойми что делает.
Собрался ставить минус? Да сам иди в жопу!

































































.
Re[5]: Сравнение + замкнутая иерархия классов ???
От: samius Япония http://sams-tricks.blogspot.com
Дата: 01.08.10 01:44
Оценка:
Здравствуйте, SpaceConscience, Вы писали:

S>>
S>>    class A
S>>    {
S>>        public override bool Equals(object obj)
S>>        {
S>>            return obj is A;
S>>        }
S>>    }

S>>    class B //: A
S>>    {
S>>        public override bool Equals(object obj)
S>>        {
S>>            return obj is A;// B;
S>>        }
S>>    }
S>>

S>>Извини, LSP по отношению к классу A не нарушена, а коммутативности нет.

SC>У тебя отличное чувство юмора. Это прикол такой? Ты привел два никак не связанных класса, для которых LSP не имеет смысла,

Почему не имеет смысла? Очень даже имеет. LSP не накладывает никаких ограничений между классами A и B.

SC> и оператор Equals при сравнении двух разнотипных объектов тоже не имеет смысла.


Во-первых не оператор, а метод Equals. Во вторых, почему не имеет смысла? Метод Object.Equals(Object) определен и не запрещен для вызова с аргументами любого типа, потому имеет смысл.
В-третьих, формально метод Equals представляет отношение равенства, которое определено как
{(x,x)| x ϵ X}

Возьмем X = {"1", 2, 3m}. Какие проблемы с проверкой отношения равенства на этом множестве?
Здесь верно лишь то, что для объектов разного типа метод Equals обязан возвращать false (даже для объектов производного типа). Иначе, отношение равенства превратится в более общее отношение эквивалентности(что видимо и пытается сделать автор), как следствие нарушится работа контейнеров, хэштаблиц и т.п. В подтверждение этому рассмотрим дурацкий пример из MSDN. Очевидно, что ThreeDPoint нельзя искать в хэштаблице с TwoDPoint-ами. Результат будет неопределен, т.к. хэшкоды у них считаются по-разному

SC>А с какого рожна здесь должна быть коммутативность-то?

Дело в том, что метод Equals призван для установления отношения равенства между объектами. А отношение равенства имеет свойство коммутативности. Проблема в том, что Equals не может гарантированно обеспечить коммутативность, как и другие свойства отношения равенства.

SC>Оператор сравнения коммутативен потому, что он утверждает равенство двух объектов, а здесь оператор сравнения не пойми что делает.

Полагаю что под оператором сравнения ты подразумеваешь метод Equals(object). Если так, то нарушена причинно-следственная связь. Метод Equals, не коммутативен, а должен быть коммутативным впринципе, но не может быть таковым в незамкнутой системе классов (не иерархии, как в заголовке темы, а в системе). Что и подтверждает мой пример.

В моем примере объявлена иерархия классов A, среди которых принято что все экземпляры A, включая любых наследников, равны между собой. Это отношение коммутативно. Но добавляем к системе урода B, и коммутативность ломается даже притом что между классами A и B нет отношения наследования.

Еще один пример, показывающий что коммутативность метода Equals не имеет отношения к наследованию и LSP:
    class A {
        public override bool Equals(object obj) {
            return obj is B;
        }
    }

    class B {
        public override bool Equals(object obj) {
            return obj is A;
        }
    }

Вот такое хитрое отношение коммутативно в замкнутой системе типов {A, B}. Оно нифига не рефлексивно и не транзитивно, потому равенством я его называть не буду.

Вообще, каким бы ни был хорошим метод Equals, грамотное со всех сторон отношение равенства он может обеспечить лишь в закрытом наборе типов, ибо Equals чрезвычайно хрупок по отношению к добавлению извне классов с неверно перекрытыми методами Equals. Отношение равенства гораздо безопаснее выражать в IComparer-ах, потому как его можно написать так, что сломать его добавлением классов извне будет невозможно.

Equals имеет лишь то преимущество, что для многих встроенных типов платформы у нас готово отношение равенства, которое можно проверить на множестве встроенных разнотипных объектов типа X = {"1", 2, 3m}. Но как только мы туда примешаем пользовательские объекты, с перекрытым методом Equals, начинается полный ахтунг. Для корректного поведения требуется выполнение всех пунктов, указанных в здесь (см. Notes to Implementers), и кроме них еще кое-чего, в том числе "true только для объектов того же типа".

Именно потому я все время настаиваю на том, чтобы отношение эквивалентности для custom иерархий реализовывать во внешнем компарере.
Re[4]: Сравнение + замкнутая иерархия классов ???
От: k.o. Россия  
Дата: 01.08.10 08:26
Оценка:
S>
S>    class A
S>    {
S>        public override bool Equals(object obj)
S>        {
S>            return obj is A;
S>        }
S>    }

S>    class B //: A
S>    {
S>        public override bool Equals(object obj)
S>        {
S>            return obj is A;// B;
S>        }
S>    }
S>

S>Извини, LSP по отношению к классу A не нарушена, а коммутативности нет.


A o1 = new A();
A o2 = new A();
Console.WriteLine(o1.Equals(o2)); // true


B o1 = new B();
B o2 = new B();
Console.WriteLine(o1.Equals(o2)); // false



Как же так, LSP не нарушен, а поведение отличается?
Re[5]: Сравнение + замкнутая иерархия классов ???
От: _FRED_ Черногория
Дата: 01.08.10 08:39
Оценка:
Здравствуйте, k.o., Вы писали:

KO>Как же так, LSP не нарушен, а поведение отличается?


В данном случае отличается не _поведение_, а результат. А то так можно договориться до того, что любой виртуальный метод, который возвращает не то же самое, что базовый класс, нарушает LSP.
Help will always be given at Hogwarts to those who ask for it.
Re[6]: Сравнение + замкнутая иерархия классов ???
От: k.o. Россия  
Дата: 01.08.10 14:13
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, k.o., Вы писали:


KO>>Как же так, LSP не нарушен, а поведение отличается?


_FR>В данном случае отличается не _поведение_, а результат. А то так можно договориться до того, что любой виртуальный метод, который возвращает не то же самое, что базовый класс, нарушает LSP.


Поведение одинаковое, входные данные тоже, а результат разный, не иначе как божественное вмешательство. И да, любой виртуальный метод, который возвращает не то же самое, что базовый класс, нарушает LSP, в чём проблема-то? Честно говоря, не хочется пересказывать содержание "Data Abstraction and Hierarchy", но если коротко, то: Иерархия типов упрощает инкрементальную разработку поскольку подтипы, не оказывают влияние на уже существующий код, использующий супертипы, а применение наследования для повторного использования реализации базового класса (возможно, с переопределением некоторых методов) интереса не представляет, поскольку такой же результат может быть достигнут с помощью делегирования.
Re[7]: Сравнение + замкнутая иерархия классов ???
От: _FRED_ Черногория
Дата: 01.08.10 14:36
Оценка:
Здравствуйте, k.o., Вы писали:

KO>>>Как же так, LSP не нарушен, а поведение отличается?


_FR>>В данном случае отличается не _поведение_, а результат. А то так можно договориться до того, что любой виртуальный метод, который возвращает не то же самое, что базовый класс, нарушает LSP.


KO>Поведение одинаковое, входные данные тоже, а результат разный, не иначе как божественное вмешательство.


Именно так.

KO>И да, любой виртуальный метод, который возвращает не то же самое, что базовый класс, нарушает LSP, в чём проблема-то?


В том, что следуя вашей логике _любой виртуальный метод_ нарушает LSP, если возвращает значенние или осуществляет side effect отличный от того, что происходит в базе. Это ошибочное мнение.

KO>Честно говоря, не хочется пересказывать содержание "Data Abstraction and Hierarchy", но если коротко, то: Иерархия типов упрощает инкрементальную разработку поскольку подтипы, не оказывают влияние на уже существующий код, использующий супертипы, а применение наследования для повторного использования реализации базового класса (возможно, с переопределением некоторых методов) интереса не представляет, поскольку такой же результат может быть достигнут с помощью делегирования.


Не вижу, какое отношение "применение наследования для повторного использования реализации базового класса" имеет к данному обсуждению И не вижу, какое отношение процитированное имеет к LSP.
Help will always be given at Hogwarts to those who ask for it.
Re[8]: Сравнение + замкнутая иерархия классов ???
От: samius Япония http://sams-tricks.blogspot.com
Дата: 01.08.10 14:55
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, k.o., Вы писали:


KO>>И да, любой виртуальный метод, который возвращает не то же самое, что базовый класс, нарушает LSP, в чём проблема-то?


_FR>В том, что следуя вашей логике _любой виртуальный метод_ нарушает LSP, если возвращает значенние или осуществляет side effect отличный от того, что происходит в базе. Это ошибочное мнение.

+1

KO>>Честно говоря, не хочется пересказывать содержание "Data Abstraction and Hierarchy", но если коротко, то: Иерархия типов упрощает инкрементальную разработку поскольку подтипы, не оказывают влияние на уже существующий код, использующий супертипы, а применение наследования для повторного использования реализации базового класса (возможно, с переопределением некоторых методов) интереса не представляет, поскольку такой же результат может быть достигнут с помощью делегирования.


_FR>Не вижу, какое отношение "применение наследования для повторного использования реализации базового класса" имеет к данному обсуждению И не вижу, какое отношение процитированное имеет к LSP.


Процитированное имеет отношение к LSP в том плане, что не нарушающие LSP подтипы не ломают код, использующий супертипы.
В принципе, я согласен с тем, что свойства отношения, выражаемого методом Object.Equals(Object), а именно рефлексивность, транзитивность, симметричность, согласованность с GetHashCode и т.п., можно отнести к свойствам контракта System.Object и применить к ним принцип LSP. Тогда реализацию "return obj is A;" можно отнести к нарушению контракта System.Object (и LSP). И действительно, такая реализация ломает код, рассчитанный на корректную реализацию метода Equals.
Re[9]: Сравнение + замкнутая иерархия классов ???
От: _FRED_ Черногория
Дата: 01.08.10 15:24
Оценка:
Здравствуйте, samius, Вы писали:

KO>>>Честно говоря, не хочется пересказывать содержание "Data Abstraction and Hierarchy", но если коротко, то: Иерархия типов упрощает инкрементальную разработку поскольку подтипы, не оказывают влияние на уже существующий код, использующий супертипы, а применение наследования для повторного использования реализации базового класса (возможно, с переопределением некоторых методов) интереса не представляет, поскольку такой же результат может быть достигнут с помощью делегирования.


_FR>>Не вижу, какое отношение "применение наследования для повторного использования реализации базового класса" имеет к данному обсуждению И не вижу, какое отношение процитированное имеет к LSP.


S>Процитированное имеет отношение к LSP в том плане, что не нарушающие LSP подтипы не ломают код, использующий супертипы.


Понятие "дломает" очень не точное: если есть код типа Debug.Assert(obj.GetType() == typeof(X)), то при чём здесь LSP?

По LSP подтип должен не "ломать код", а не нарушать инварианты. Мне кажется инвариант "метод M() должен возвращать N" не имеет смысла.

S>В принципе, я согласен с тем, что свойства отношения, выражаемого методом Object.Equals(Object), а именно рефлексивность, транзитивность, симметричность, согласованность с GetHashCode и т.п., можно отнести к свойствам контракта System.Object и применить к ним принцип LSP. Тогда реализацию "return obj is A;" можно отнести к нарушению контракта System.Object (и LSP). И действительно, такая реализация ломает код, рассчитанный на корректную реализацию метода Equals.


Покажи пожалуйста, какие из инвариантов метода Object::Equals(object) нарушил пример TK здесь
Автор: TK
Дата: 31.07.10
?

The following statements must be true for all implementations of the Equals method. In the list, x, y, and z represent object references that are not null.

  • x.Equals(x) returns true, except in cases that involve floating-point types. See IEC 60559:1989, Binary Floating-point Arithmetic for Microprocessor Systems.
  • x.Equals(y) returns the same value as y.Equals(x).
  • x.Equals(y) returns true if both x and y are NaN.
  • (x.Equals(y) && y.Equals(z)) returns true if and only if x.Equals(z) returns true.
  • Successive calls to x.Equals(y) return the same value as long as the objects referenced by x and y are not modified.
  • x.Equals(null) returns false.

  • Разве что GetHashCode() не приведён, но его реализация в данном случае примитивна и не интересна.
    Help will always be given at Hogwarts to those who ask for it.
    Re[10]: Сравнение + замкнутая иерархия классов ???
    От: samius Япония http://sams-tricks.blogspot.com
    Дата: 01.08.10 15:32
    Оценка:
    Здравствуйте, _FRED_, Вы писали:

    _FR>>>Не вижу, какое отношение "применение наследования для повторного использования реализации базового класса" имеет к данному обсуждению И не вижу, какое отношение процитированное имеет к LSP.


    S>>Процитированное имеет отношение к LSP в том плане, что не нарушающие LSP подтипы не ломают код, использующий супертипы.


    _FR>Понятие "дломает" очень не точное: если есть код типа Debug.Assert(obj.GetType() == typeof(X)), то при чём здесь LSP?


    _FR>По LSP подтип должен не "ломать код", а не нарушать инварианты.

    Да, согласен. "ломать" — это неудачный термин.

    _FR>Мне кажется инвариант "метод M() должен возвращать N" не имеет смысла.

    Нечто подобное утверждал k.o..

    S>>В принципе, я согласен с тем, что свойства отношения, выражаемого методом Object.Equals(Object), а именно рефлексивность, транзитивность, симметричность, согласованность с GetHashCode и т.п., можно отнести к свойствам контракта System.Object и применить к ним принцип LSP. Тогда реализацию "return obj is A;" можно отнести к нарушению контракта System.Object (и LSP). И действительно, такая реализация ломает код, рассчитанный на корректную реализацию метода Equals.


    _FR>Покажи пожалуйста, какие из инвариантов метода Object::Equals(object) нарушил пример TK здесь
    Автор: TK
    Дата: 31.07.10
    ?

    _FR>

    _FR>The following statements must be true for all implementations of the Equals method. In the list, x, y, and z represent object references that are not null.
    _FR>

  • x.Equals(x) returns true, except in cases that involve floating-point types. See IEC 60559:1989, Binary Floating-point Arithmetic for Microprocessor Systems.
    _FR>
  • x.Equals(y) returns the same value as y.Equals(x).
    _FR>
  • x.Equals(y) returns true if both x and y are NaN.
    _FR>
  • (x.Equals(y) && y.Equals(z)) returns true if and only if x.Equals(z) returns true.
    _FR>
  • Successive calls to x.Equals(y) return the same value as long as the objects referenced by x and y are not modified.
    _FR>
  • x.Equals(null) returns false.


  • Выделил. TK и сам об этом написал.
    Re[11]: Сравнение + замкнутая иерархия классов ???
    От: _FRED_ Черногория
    Дата: 01.08.10 16:37
    Оценка:
    Здравствуйте, samius, Вы писали:

    _FR>>Покажи пожалуйста, какие из инвариантов метода Object::Equals(object) нарушил пример TK здесь
    Автор: TK
    Дата: 31.07.10
    ?

    _FR>>

  • x.Equals(y) returns the same value as y.Equals(x).


  • S>Выделил. TK и сам об этом написал.


    Точно.
    Help will always be given at Hogwarts to those who ask for it.
    Re[8]: Сравнение + замкнутая иерархия классов ???
    От: k.o. Россия  
    Дата: 02.08.10 14:37
    Оценка:
    Здравствуйте, _FRED_, Вы писали:

    _FR>Здравствуйте, k.o., Вы писали:


    KO>>>>Как же так, LSP не нарушен, а поведение отличается?


    _FR>>>В данном случае отличается не _поведение_, а результат. А то так можно договориться до того, что любой виртуальный метод, который возвращает не то же самое, что базовый класс, нарушает LSP.


    KO>>Поведение одинаковое, входные данные тоже, а результат разный, не иначе как божественное вмешательство.


    _FR>Именно так.


    А может всё-таки причины более прозаические, например, изменение поведения?

    KO>>И да, любой виртуальный метод, который возвращает не то же самое, что базовый класс, нарушает LSP, в чём проблема-то?


    _FR>В том, что следуя вашей логике _любой виртуальный метод_ нарушает LSP, если возвращает значенние или осуществляет side effect отличный от того, что происходит в базе. Это ошибочное мнение.


    Хорошо, про _любой_ метод это неверное утверждение (неаккуратный копипаст твоих же слов ), LSP нарушается если контракт подтипа не соответсвует (как в обсуждаемом случае с переопределением Equals) контракту базового типа. Возвращаясь к примеру: код использующий A имеет полное право ожидать, что для любых двух объектов типа A, метод Equals вернёт true, тип B этому ожиданию не соответствует, поэтому не может быть подтипом A.

    _FR>Не вижу, какое отношение "применение наследования для повторного использования реализации базового класса" имеет к данному обсуждению И не вижу, какое отношение процитированное имеет к LSP.


    Это не цитата, а краткий пересказ некоторых моментов из статьи Б. Лисков "Data Abstraction and Hierarchy", в которой и описывается LSP.
    Re[9]: Сравнение + замкнутая иерархия классов ???
    От: _FRED_ Черногория
    Дата: 02.08.10 14:48
    Оценка:
    Здравствуйте, k.o., Вы писали:

    KO>Возвращаясь к примеру: код использующий A имеет полное право ожидать, что для любых двух объектов типа A, метод Equals вернёт true, тип B этому ожиданию не соответствует, поэтому не может быть подтипом A.


    Да, в данном случае действительно перегрузка не корректная.
    Help will always be given at Hogwarts to those who ask for it.
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.