Вопрос

Возможный дубликат:
Почему изменяемые структуры — это зло?

Я читал во многих местах, в том числе и здесь, о том, что структуры лучше делать неизменяемыми.

В чем причина этого?Я вижу множество изменяемых структур, созданных Microsoft, например, в xna.Вероятно, в BCL их гораздо больше.

Каковы плюсы и минусы несоблюдения этого правила?

Это было полезно?

Решение

Структуры должны представлять ценности.Ценности не меняются.Число 12 вечно.

Однако учтите:

Foo foo = new Foo(); // a mutable struct
foo.Bar = 27;
Foo foo2 = foo;
foo2.Bar = 55;

Теперь foo.Bar и foo2.Bar отличаются, что часто бывает неожиданно.Особенно в таких сценариях, как свойства (к счастью, компилятор это обнаруживает).Но также коллекции и т. д.;как их разумно мутировать?

Потеря данных слишком проста с изменяемыми структурами.

Другие советы

Большим минусом является то, что вещи ведут себя не так, как вы ожидаете, особенно если изменчивость возникает из-за сочетания прямого значения и ссылочного типа внутри него.

Честно говоря, я не могу сразу вспомнить все странные проблемы, с которыми я видел людей в группах новостей, когда они использовали изменяемые структуры - но такие причины определенно существуют. Изменяемые структуры вызывают проблемы. Держись подальше.

РЕДАКТИРОВАТЬ:Я только что нашел письмо, которое я написал некоторое время назад на эту тему.Он немного уточняет:

  • Философски неверно:структура должна представлять какую-то фундаментальную ценность.Они в основном неизменны.Вы не можете изменить цифру 5.Вы можете изменить значение переменной с 5 на 6, но логически вы не меняете само значение.

  • Это практически проблема:это создает много странных ситуаций.Особенно плохо, если его можно изменить через интерфейс.Затем вы можете начать изменять значения в коробках.Ик.Я видел много сообщений в группах новостей из-за того, что люди пытались использовать изменяемые структуры и сталкивались с проблемами.Я видел очень странный пример LINQ, который не удался, потому что List<T>.Enumerator это структура, например.

Я часто использую изменяемые структуры в своем (критическом к производительности) проекте - и у меня не возникает проблем, поскольку я понимаю последствия семантики копирования.Насколько я могу судить, основная причина, по которой люди выступают за неизменяемые структуры, заключается в том, что люди, которые не понимать последствия, не может навлечь на себя неприятности.

Это не такая уж и ужасная вещь — но сейчас мы находимся в опасности, что это станет «евангельской истиной», хотя на самом деле бывают случаи, когда сделать структуру изменяемой — это законно лучший вариант.Как и во всем, есть исключения из правил.

Нет ничего более дешевого в манипулировании, чем изменяемая структура, поэтому вы часто видите ее в высокопроизводительном коде, например, в процедурах обработки графики.

К сожалению, изменяемые структуры плохо сочетаются с объектами и свойствами: слишком легко изменить копию структуры вместо самой структуры.Таким образом, они не подходят для большей части вашего кода.

P.S.Чтобы избежать затрат на копирование изменяемых структур, они обычно хранятся и передаются в массивах.

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

public void DoSomething(MySomething something)
{
    something.Property = 10;
}

Ведёт себя совершенно по-разному в зависимости от того, MySomething это struct или class.Для меня это веская, но не самая веская причина.Если вы посмотрите на ДДД's Объект значения, вы можете увидеть связь с тем, как следует обращаться со структурами.Объект значения в DDD лучше всего представить как тип значения в .Net (и, следовательно, как структуру).Поскольку у него нет идентичности, он не может измениться.

Подумайте об этом как о чем-то вроде вашего адреса.Вы можете «изменить» свой адрес, но сам адрес не изменится.Фактически, вам присвоен новый адрес.Концептуально это работает, потому что если вы действительно измененный ваш адрес, вашим соседям по комнате тоже придется переехать.

Вы спросили о плюсах и минусах нет следуя принципу, согласно которому структуры должны быть неизменяемыми.

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

Плюсы: Основным плюсом использования изменяемых структур может быть производительность.Очевидно, что этот совет сопровождается всеми обычными предостережениями по поводу оптимизации:убедитесь, что эта часть вашего кода потребности быть оптимизированным и убедиться, что любые изменения действительно оптимизируют производительность вашего кода посредством профилирования.

Отличная статья о том, когда вам может понадобиться использовать изменяемые структуры, см. в статье Рико Мариани. Тест на производительность по ценностно-ориентированному программированию (или, точнее, ответы).

Структура обычно должна представлять собой какое-то единое целое.Таким образом, нет особого смысла изменять одно из свойств значения, имеет смысл создать совершенно новое значение, если вам нужно значение, которое каким-то образом отличается.

Семантика становится проще при использовании неизменяемых структур, и вы избегаете таких ошибок:

// a struct
struct Interval {
   int From { get; set; }
   int To { get; set; }
}

// create a list of structs
List<Interval> intervals = new List<Interval>();

// add a struct to the list
intervals.Add(new Interval());

// try to set the values of the struct
intervals[0].From = 10;
intervals[0].To = 20;

В результате структура в списке вообще не меняется.Выражение Interval[0] копирует значение структуры из списка, затем вы меняете свойство временного значения, но значение никогда не возвращается в список.

Редактировать:Изменен пример, чтобы использовать список вместо массива.

Когда вы копируете структуры, вы копируете их содержимое, поэтому, если вы измените скопированную версию, «оригинал» не будет обновлен.

Это источник ошибок, поскольку даже если вы знаете, что попадаете в ловушку копирования структуры (просто путем передачи ее методу) и изменения копии.

Только что случилось со мной снова на прошлой неделе мне пришлось целый час искать ошибку.

Сохранение неизменяемости структур предотвращает это...

Кроме этого, вам нужно убедиться, что у вас есть действительно веская причина для использования структур - «оптимизация» или «я хочу что-то, что быстро распределяется в стеке» не считается ответом.Маршалинг или вещи, где вы зависите от макета — хорошо, но обычно вам не следует хранить эти структуры очень долго, они являются значениями, а не объектами.

причина, по которой вам следует делать структуры неизменяемыми, заключается в том, что они Типы значений, что означает, что они копируются каждый раз, когда вы передаете их методу.

Так, если, например, у вас есть свойство, возвращающее структуру, изменение значения поля в этой структуре будет бесполезным, поскольку метод получения вернет копировать структуры, а не ссылку на структуру.Я видел это в коде, и зачастую это сложно уловить.

Если вы проектируете свои структуры с учетом неизменяемости, вы помогаете программисту избежать этих ошибок.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top