Pull to refresh

Comments 21

«No matter what type is involved, a == a is always true.»

На самом деле, для платформы .NET это правило исполняется не всегда. А вы можете привести пример, когда это условие нарушается?

double.NaN == double.NaN
Или когда оператор переопределён и возвращает true/false в зависимости от Random :)
Или вообще сделать чтобы всегда false возвращало.
   class Program {
        static int cntr=0;
        static int a { get { return ++cntr; } }
        static void Main(string[] args) {
            Console.WriteLine("{0}",a==a);
        }
    }

Напечатала false. Безо всяких переопределений сравнения.
В данном случае a — это выражение с побочными эффектами. Конечно же, два последовательных вызова метода могут возвращать разный результат.

Речь же идет о том, есть ли тип, желательно в BCL, для которого рефлексивность оператора == не выполняется.
>> Любой программист, пришедший в .NET из С++ ответит положительно (ведь так быстрее!), потом он прочитает о проблемах и его мнение наверняка изменится на противоположное.

Ни один программист пришедший из c++ никогда не изменит свое мнение. В с++ это не считается проблемами, в с++ весь геморой которым борешься пол жизни считается наградой, выслугой лет.
А те кто изменяет свое мнение (например после шарпа), никогда не возвращается назад в с++.
Я же не пишу о возврате в С++, но многие мои коллеги, пришедшие из С++ изменяют свое отношение к структурам в .NET-е, после понимания количества проблем, которые могут с ними произойти.
Неточность #3. Об операторе ==
«No matter what type is involved, a == a is always true.»

Это предложение не является неточностью, оно очень неудачно выдернуто из контекста:

… you need to keep in mind the mathematical properties of equality: Equality is reflexive, symmetric, and transitive. The reflexive property means that any object is equal to itself. No matter what type is involved, a == a is always true.

То есть
a == a is always true
это всего лишь определение рефлексивности.

Вообще же автор пишет о том, как должен работать оператор сравнения в том случае если программист решит его переопределить, а не о том как он на самом деле работает.
Спасибо за добавление контекста, в этом случае неточность становится более четкой:) Дело в том, что в .NET-е, рефлексивность обязан обеспечивать метод Equals, но ее нет у оператора ==.
Это одна из причин (помимо того, что оператор == не полиморфный), почему для определения эквивалентности объектов в том же Dictionary используется именно Equals, а не оператор ==.

И Double.NaN является известным примером, когда Equals остается рефлексивным, а оператор == — нет.
Если я не ошибаюсь, NaN по стандарту себе не равен, и не только для C#, что предполагает, что NaN не принадлежит типу, для которого должна обеспечиваться рефлексивность.
double.NaN хитрый зверь:

double.NaN.Equals(double.NaN) — true
double.NaN == double.NaN — false

Просто если бы не работал Equals, то вы бы не смогли из словаря double.NaN достать.
Equals видимо не подпадает видимо под действие стандарта.

На википедии, кстати, написано, NaN себе не равен по стандарту IEEE 754. И там кстати также написано, почему так. NaN может быть получен от деления на ноль, от извлечения корня из отрицательного числа, и т.п. Записывается результат одинаково, а вот получить равенство результатов вышеперечисленных операций было бы фейлом.

Так что с рефлексивностью у оператора == все в порядке.
Неточность #5. Порядок создания объектов
Выглядит как вырванное из контекста. Ну т.е. при создании экземпляра операции действительно выполняются в таком порядке. Аналогично:
1. Static variable storage is set to 0.
— если статических членов нет, то и устанавливаться в ноль ничего не будет.
Речь немного не об этом. Речь о выделенном, что при создании экземпляра вначале вызывается статический конструктор базового класса, а потом статический конструктор наследника. В некоторых случаях (при наличии атрибута beforefieldinit у типа), при создании экземпляра наследника даже вызов статического конструктора наследника не гарантируется (подробности здесь).

Но даже в базовом случае, порядок вызова статических конструкторов противоположен порядку вызова экземплярных конструкторов: экземплярные конструкторы взываются от базового к наследнику, а статические конструкторы — от наследника к базовому.

Вот пруф:

internal class Base
{
    public Base()
    {
        Console.WriteLine("Base.ctor");
    }

    static Base()
    {
        Console.WriteLine("Base.cctor");
    }
}
    
internal class Derived : Base
{
    public Derived()
    {
        Console.WriteLine("Derived.ctor");
    }

    static Derived()
    {
        Console.WriteLine("Derived.cctor");
    }
}


При вызове new Derived() на экране мы получим следующее:

Derived.cctor Base.cctor Base.ctor Derived.ctor
Я в свое время заказал на Амазоне и Скита, и Вагнера в одной посылке. Сначала прочитал Скита и был в диком восторге. А потом прочитал Вагнера и остался разочарован. Мне не понравилась ультимативность стиля изложения как таковая. Некоторые советы показались надуманными. И да, минимум объяснений на контрасте со Скитом смотрелось очень неинтересно. Книга имеет право на жизнь, но почему она стоит столько же, сколько и «C# in Depth», я не понимаю.
мой совет: сначала прочитать CLR via C#, а потом уже Effective C#, и при расхождениях верить первой книжке.
При расхождениях — лезть в спецификацию.
А что может автор данной статьи рассказать о плюсах данной книги? Указанные недочеты — это не вся книга.
Из плюсов: довольно приличное количество мыслей для размышлений, разбитых по разделам. Начинаешь читать главы по Equals/GetHashCode, любые несогласия с автором вынуждают к определенному ресерчу, который позволяет понять, где же на самом деле правда. И таких «вбросов» достаточно много; на часть из них сам автор дает вменяемые ответы, а вот ответы на другие вбросы придется искать в другом месте.

Возможно недостатки подпортили впечатление сильнее, в результате чего положительные моменты не так сильно отпечатались в памяти. Все будет зависеть от того, что вы читали до этого. Если для вас в книге Скита не много нового, то эту книгу нет смысла читать. Если же у вас пара лет опыта работы с платформой .NET и языком C#, то в книге Вагнера будет много полезного.
А русскоязычный вариант есть?
Sign up to leave a comment.

Articles