Случаи использования для упаковки типа значения в C#?

StackOverflow https://stackoverflow.com/questions/1028520

Вопрос

Бывают случаи, когда экземпляр Тип значения должен рассматриваться как ссылочного типа. Для ситуации, подобные этой, тип значения экземпляр может быть преобразован в ссылочного типа через экземпляр Процесс, называемый упаковкой.Когда значение type instance упакован, storage выделенного в кучу, а instance копируется в пространство.Ссылка на это хранилище помещается в стек.Упакованное значение является объектом, ссылочным типом, который содержит содержимое значения Тип экземпляра.

Понимание системы общих типов .NET

В Википедия есть пример для Java.Но в каких случаях в C# придется упаковать тип значения?Или лучший/похожий вопрос: зачем хранить тип значения в куче (в штучной упаковке), а не в стеке?

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

Решение

В общем, вы, как правило, хотите избегать упаковки типов значений.

Однако, есть редкие случаи, когда это полезно. Например, если вам нужно ориентироваться на платформу 1.1, у вас не будет доступа к универсальным коллекциям. Любое использование коллекций в .NET 1.1 потребует обработки вашего типа значения как System.Object, что приведет к упаковке / распаковке.

Есть еще случаи, когда это может быть полезно в .NET 2.0+. В любое время, когда вы хотите воспользоваться тем фактом, что все типы, включая типы значений, могут рассматриваться как объект напрямую, вам может понадобиться использовать упаковку / распаковку. Иногда это может быть удобно, поскольку позволяет сохранять любой тип в коллекции (используя объект вместо T в универсальной коллекции), но в целом этого лучше избегать, поскольку вы теряете безопасность типов. Тем не менее, один из случаев, когда бокс часто происходит, - это когда вы используете Reflection. Многие вызовы в отражении требуют бокса / распаковки при работе с типами значений, так как тип заранее неизвестен.

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

Почти никогда нет веских причин для преднамеренного размещения типа значения. Почти всегда причина помещать значение в тип значения состоит в том, чтобы сохранить его в некоторой коллекции, которая не знает тип. Старый ArrayList , например, является коллекцией объектов, которые являются ссылочными типами. Единственный способ собрать, скажем, целые числа, это пометить их как объекты и передать их в ArrayList.

В настоящее время у нас есть общие коллекции, так что это не проблема.

Бокс обычно происходит автоматически в .NET, когда это необходимо; часто, когда вы передаете тип значения чему-то, что ожидает ссылочный тип. Типичным примером является string.Format (). Когда вы передаете примитивные типы значений этому методу, они помещаются в рамку как часть вызова. Итак:

int x = 10;
string s = string.Format( "The value of x is {0}", x ); // x is boxed here

Это иллюстрирует простой сценарий, в котором тип значения (x) автоматически упаковывается для передачи в метод, который ожидает объект. Как правило, вы хотите по возможности избегать типов значений бокса ... но в некоторых случаях это очень полезно.

Интересно отметить, что при использовании обобщений в .NET типы значений не заключаются в квадраты при использовании в качестве параметров или членов типа. Что делает дженерики более эффективными, чем более старый код C # (например, ArrayList), который рассматривает все как {объект} как независимый от типа. Это добавляет еще одну причину использования общих коллекций, таких как List<T> или Dictionary<T,K> поверх ArrayList или Hashtable.

Я бы порекомендовал вам 2 замечательные статьи Эрика Липперта.

http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx

http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx

Вот цитата, с которой я согласен на 100%.

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

В 99% разработчиков приложений не должно волновать, почему типы Value находятся в стеке, а не в куче и какой прирост производительности мы можем здесь получить.Юты имеют в виду очень простые правила:

  1. Избегайте упаковки/распаковки, когда это не так Необходимо использовать универсальные коллекции.Большинство проблем возникает не тогда, когда вы определите свои собственные типы, но когда вы Неправильное использование существующих типов (определено корпорацией Майкрософт или вашим коллеги)
  2. Создание типов значений простой.Если вам нужно иметь структуру с 10-20 полями, я полагаю, что вы Лучше создайте класс.Представьте себе, все что поля будут копироваться каждый раз Когда вы время от времени передаете ему функция по значению...
  3. Я не думаю, что это очень полезно Типы значений со ссылочным типом поля внутри.Like struct с Строковые и объектные поля.
  4. Определите, какой тип вам нужен, в зависимости от требуемая функциональность, а не где Его следует хранить.Структуры имеют ограниченная функциональность по сравнению с классов, поэтому, если struct не может предоставить требуемая функциональность, например, Конструктор по умолчанию, определите класс.
  5. Если что-то может выполнить какое-либо действия с данными других типы, обычно он определяется как класс.Для операций со структурами с Должны быть определены различные типы только в том случае, если вы можете привести один тип к другой.Допустим, вы можете добавить int к double, потому что вы можете привести int к двойной.
  6. Если что-то должно быть без гражданства, так это класс.
  7. Когда вы колеблетесь, используйте ссылочные типы.:-)

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

п.с.Я встречал разработчиков ASP.NET с 2-3-летним опытом, которые не знали разницы между стеком и кучей.:-( Я бы не нанял такого человека, если бы я был интервьюером, но не потому, что упаковка/распаковка может быть узким местом на любом из сайтов ASP.NET, которые я когда-либо видел.

Я думаю, что хороший пример бокса в c # встречается в неуниверсальных коллекциях, таких как ArrayList .

Один пример, когда метод принимает параметр объекта и тип значения должен быть передан.

Ниже приведены некоторые примеры упаковки / распаковки

ArrayList ints = new ArrayList();
myInts.Add(1); // boxing
myInts.Add(2); // boxing

int myInt = (int)ints [0]; // unboxing

Console.Write("Value is {0}", myInt); // boxing

Одна из ситуаций, когда это происходит, например, если у вас есть метод, который ожидает параметр типа объекта, и вы передаете один из примитивных типов, например, int. Или если вы определяете параметр как 'ref' типа int.

Код

int x = 42;
Console.Writeline("The value of x is {0}", x );

на самом деле ящики и ящики, потому что Writeline выполняет приведение int внутрь. Чтобы избежать этого, вы можете сделать

int x = 42;
Console.Writeline("The value of x is {0}", x.ToString());

Остерегайтесь мелких ошибок!

Вы можете объявить свои собственные типы значений, объявив свой собственный тип как struct. Представьте, что вы объявляете ArrayList с множеством свойств, а затем помещаете несколько экземпляров в []. Это коробки их, конечно. Теперь обратитесь к одному через оператор readonly, приведите его к типу и установите свойство. Вы просто устанавливаете свойство для copy . Тот, что в <=>, остается неизменным.

По этой причине типы значений всегда должны быть неизменяемыми, т. е. делать все переменные-члены <=> так, чтобы они могли быть установлены только в конструкторе и не иметь никаких изменяемых типов в качестве членов.

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