Почему нам нужны упаковка и распаковывание в C#?

Почему нам нужны упаковка и распаковывание в C#?

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

short s = 25;

object objshort = s;  //Boxing

short anothershort = (short)objshort;  //Unboxing
306
задан kame 27 December 2017 в 23:35
поделиться

6 ответов

Зачем

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

Подумайте об этом вот так. Имеется переменная o типа object . Теперь у вас есть int , и вы хотите поместить его в o . o - это отсылка к чему-то где-то, а int - это явно не отсылка к чему-то где-то (в конце концов, это просто число). Итак, вы делаете новый объект , который может хранить int , а затем присваиваете ссылку на этот объект o . Мы называем этот процесс «боксом».

Итак, если вы не хотите иметь унифицированную систему типов (т.е. ссылочные типы и типы значений имеют очень разные представления, и вы не хотите, чтобы общий способ «представить» два), то вам не нужен бокс. Если вы не заботитесь о том, чтобы int представляли их базовое значение (т.е. вместо этого int также были ссылочными типами и просто хранили ссылку на их базовое значение), то вам не нужна бокс.

где мне его использовать.

Например, старый тип коллекции ArrayList ест только объекты . То есть в нем хранятся только отсылки к тому, что где-то живет. Без бокса в такую коллекцию нельзя положить int . Но с боксом можно.

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

Это правильно:

double e = 2.718281828459045;
int ee = (int)e;

Это не так:

double e = 2.718281828459045;
object o = e; // box
int ee = (int)o; // runtime exception

Вместо этого вы должны сделать это:

double e = 2.718281828459045;
object o = e; // box
int ee = (int)(double)o;

Сначала мы должны явным образом разблокировать double ( (double) o ), а затем выдать это int .

Каков результат:

double e = 2.718281828459045;
double d = e;
object o1 = d;
object o2 = e;
Console.WriteLine(d == e);
Console.WriteLine(o1 == o2);

Подумайте об этом секунду, прежде чем перейти к следующему предложению.

Если вы сказали Истина и Ложь отлично! Подожди, что? Это потому, что = = для ссылочных типов использует ссылочное равенство, которое проверяет, равны ли ссылки, а не равны ли базовые значения. Это опасно легкая ошибка. Возможно, еще более тонкий

double e = 2.718281828459045;
object o1 = e;
object o2 = e;
Console.WriteLine(o1 == o2);

также напечатает Ложь !

Лучше сказать:

Console.WriteLine(o1.Equals(o2));

который затем, к счастью, напечатает True .

Последняя тонкость:

[struct|class] Point {
    public int x, y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

Point p = new Point(1, 1);
object o = p;
p.x = 2;
Console.WriteLine(((Point)o).x);

Каков результат? Это зависит! Если Пункт является структурой , то выводом является 1 , но если Пункт является классом , то выводом является 2 ! При конвертировании бокса создается копия упаковываемого значения, объясняющая разницу в поведении.

461
ответ дан 23 November 2019 в 01:19
поделиться

Когда метод принимает только тип ссылочного типа в качестве параметра (скажем, общий метод ограничен, чтобы быть классом через ограничение NEW ), вы не сможете пройти Ссылочный тип к нему и должен вставлять его.

Это также верно для любых методов, которые берут объект в качестве параметра - это будет , чтобы быть эталонным типом.

0
ответ дан 23 November 2019 в 01:19
поделиться

В рамках .NET есть два вида типов - типы значений и типов знаков. Это относительно распространено в языках ОО.

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

Теперь, вернувшиеся в старые дни (1.0 Microsoft.net), не было ли этих новообразованных генеризмов Hullabaloo. Вы не можете написать метод, который имел один аргумент, который мог бы обслуживать тип значения и тип ссылки. Это нарушение полиморфизма. Таким образом, бокс был принят в качестве средства, чтобы принудительно привлечь ценность в объекте.

Если это было невозможно, структура будет изменена методами и классами, единственная цель которых должна была принять другие виды типа. Не только то, что, но поскольку типы ценностей не имеют действительно общего предка типа, вам нужно иметь другой перегрузку метода для каждого типа значения (бит, байт, INT16, INT32 и т. Д.).

Бокс помешал этому. И вот почему британцы празднуют день бокса.

52
ответ дан 23 November 2019 в 01:19
поделиться

Бокс и распаковка специально используются для лечения объектов типа значения в качестве эталонного типа; Перемещая свою фактическую ценность для управляемой кучи и доступа к их стоимости посредством ссылки.

без бокса и распаковки вы никогда не сможете пройти типы значений посредством ссылки; И это означает, что вы не могли пройти типы ценностей как экземпляры объекта.

12
ответ дан 23 November 2019 в 01:19
поделиться

Последнее место, где я должен был что-то разблокировать, было при написании кода, который получил некоторые данные из базы данных (я не использовал LINQ в SQL , просто простой старый ADO.NET ):

int myIntValue = (int)reader["MyIntValue"];

В основном, если вы работаете со старыми API до дженериков, вы столкнетесь с боксом. Кроме этого, это не так часто встречается.

-121--54360-

Бокс на самом деле не является тем, что вы используете - это то, что использует среда выполнения, чтобы вы могли обрабатывать ссылки и значения типов в одном и том же пути, когда это необходимо. Например, если для хранения списка целых чисел используется ArrayList, целые числа помещаются в слоты объектного типа в ArrayList.

Используя общие коллекции сейчас, это в значительной степени уходит. Если создать Список < int > , бокс не будет выполнен - Список < int > может содержать целые числа напрямую.

20
ответ дан 23 November 2019 в 01:19
поделиться

Последнее место, где мне приходилось распаковывать что-то, было при написании кода, который извлекал некоторые данные из базы данных (я не использовал LINQ to SQL , просто старый добрый ADO.NET ]):

int myIntValue = (int)reader["MyIntValue"];

В основном, если вы работаете со старыми API до создания дженериков, вы столкнетесь с боксом. В остальном это не так уж часто.

7
ответ дан 23 November 2019 в 01:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: