МИФ № 1: СТРУКТЫ - ЛЕГКИЕ КЛАССЫ
Этот миф имеет множество форм. Некоторые люди считают, что типы значений не могут или
не должно иметь методов или другого значимого поведения - их следует использовать как простые
типы передачи данных, только с открытыми полями или простыми свойствами. Тип DateTime является
хороший контрпример к этому: имеет смысл для него быть типом значения, с точки зрения
фундаментальная единица, такая как число или символ, и также имеет смысл для него быть
способен выполнять расчеты на основе его стоимости. Глядя на вещи с другой
направление, типы передачи данных часто должны быть ссылочными типами в любом случае - решение
должны основываться на желаемом значении или семантике ссылочного типа, а не на простоте
тип.
Другие люди считают, что типы значений «легче», чем ссылочные типы в терминах
производительности. Правда в том, что в некоторых случаях типы значений более производительны -
им не требуется сборка мусора, если они не упакованы, не имеют тип
накладные расходы на идентификацию и не требуют разыменования, например. Но в других
пути, ссылочные типы более производительны - передача параметров, присвоение значений
Переменные, возвращаемые значения и подобные операции требуют только 4 или 8 байтов для копирования (в зависимости от того, используете ли вы 32-разрядную или 64-разрядную версию CLR), а не
копирование всех данных. Представьте, что ArrayList был каким-то «чистым» типом значения, и
Передача выражения ArrayList методу, включающему копирование всех его данных! Почти
во всех случаях производительность не зависит от такого рода решений. Узкие места почти никогда не бывают такими, какими вы их считаете, и прежде чем принимать проектное решение, основанное на производительности, вы должны измерить различные варианты.
Стоит отметить, что сочетание двух убеждений тоже не работает. Это
не имеет значения, сколько методов имеет тип (будь то класс или структура) -
память, взятая за экземпляр, не затрагивается. (Там есть стоимость с точки зрения памяти
взят за сам код, но это происходит один раз, а не для каждого экземпляра.)
МИФ № 2: СПРАВОЧНЫЕ ТИПЫ ЖИВАЯ НА КРУГЕ; ЦЕННЫЕ ТИПЫ ЖИТЬ НА СТЕКЕ
Это часто вызывается ленью повторяющего его человека. Первый
часть верна - экземпляр ссылочного типа всегда создается в куче. Это
Вторая часть, которая вызывает проблемы. Как я уже отмечал, значение переменной живет везде, где она объявлена, поэтому, если у вас есть класс с переменной экземпляра типа int, значение этой переменной для любого данного объекта всегда будет там, где остальные данные для объекта
это в куче. Только локальные переменные (переменные, объявленные в методах) и метод
параметры живут в стеке. В C # 2 и более поздних версиях даже некоторые локальные переменные
жить в стеке, как вы увидите, когда мы рассмотрим анонимные методы в главе 5.
СООТВЕТСТВУЮТ ЛИ ЭТИ КОНЦЕПЦИИ СЕЙЧАС? Можно утверждать, что если вы пишете управляемый код, вы должны позволить среде выполнения беспокоиться о том, как лучше всего использовать память.
Действительно, спецификация языка не дает никаких гарантий о том, что живет
где; будущая среда выполнения может создать несколько объектов в стеке, если
знает, что это может сойти с рук, или компилятор C # может генерировать код, который
вряд ли использует стек вообще.
Следующий миф обычно является просто вопросом терминологии.
МИФ № 3: ОБЪЕКТЫ ПРОЙДЕНЫ ПО ССЫЛКЕ В C # ПО УМОЛЧАНИЮ
Это, наверное, самый распространенный миф. Опять же, люди, которые делают это
утверждают, часто (хотя и не всегда) знают, как на самом деле ведет себя C #, но они не знают
что на самом деле означает «передать по ссылке». К сожалению, это сбивает с толку людей, которые
знаю, что это значит.
Формальное определение передачи по ссылке относительно сложное, включающее l-значения
и подобная компьютерная терминология, но важно то, что если вы передадите
переменная по ссылке, метод, который вы вызываете, может изменить значение cпеременная аллерга путем изменения значения его параметра. Теперь помните, что значение ссылки
Переменная типа - это ссылка, а не сам объект. Вы можете изменить содержимое
объект, на который ссылается параметр без передачи самого параметра по ссылке. Например, следующий метод изменяет содержимое StringBuilder
объект, о котором идет речь, но выражение вызывающего все равно будет ссылаться на тот же объект, что и
раньше:
void AppendHello(StringBuilder builder)
{
builder.Append("hello");
}
Когда этот метод вызывается, значение параметра (ссылка на StringBuilder)
передается по значению. Если бы вы изменили значение переменной построителя в
метод - например, с помощью оператора builder = null; - это изменение не будет
видел вызывающий, вопреки мифу.
Интересно отметить, что не только бит «по ссылке» мифа неточен, но и бит «объекты переданы». Сами объекты никогда не передаются, либо
по ссылке или по значению. Когда задействован ссылочный тип, либо переменная
передается по ссылке или значение аргумента (ссылка) передается по значению.
Помимо всего прочего, это отвечает на вопрос, что происходит, когда ноль
используется в качестве аргумента по значению - если объекты передаются, это приведет к
проблемы, так как не было бы объекта для передачи! Вместо этого нулевая ссылка передается
значение так же, как и любая другая ссылка.
Если это быстрое объяснение оставило вас в замешательстве, вы можете посмотреть мою статью «Передача параметров в C #» (http://mng.bz/otVt),, которая затрагивает гораздо больше
подробно.
Эти мифы не единственные вокруг. Бокс и распаковка приходят за своими
справедливая доля недоразумений, которые я постараюсь прояснить в следующем.
Справка: C # в 3-м издании по глубине от Jon Skeet