Осуществляется ли упаковка / распаковка посредством позднего или раннего связывания (т.е. во время выполнения или во время компиляции)? - PullRequest
1 голос
/ 07 декабря 2011

Например:

int i=10;
object o = i; //late or early??

Аналогично,

object o = "11";
int i = (int)o;//late or early??

Ответы [ 4 ]

8 голосов
/ 07 декабря 2011

Осуществляется ли упаковка и распаковка посредством позднего или раннего связывания? То есть привязка выполняется во время выполнения или во время компиляции?

Я немного смущен этим вопросом. «Связывание» обычно используется для обозначения результата какого-либо анализа. «Раннее связывание» обычно означает, что какое-то имя было связано с некоторым слотом метода во время компиляции; «Позднее связывание» связывает имя со слотом во время выполнения. Что вы подразумеваете под «связыванием» здесь в контексте бокса?

Полагаю, вы хотите сказать, что позднее связывание вступает в действие только для вызовов методов и методов, а не для операций присваивания / преобразования типов. Для реализации динамического связывания мы ссылаемся на производные объекты с переменными базового класса.

Это не совсем то, что я имел в виду; Я использовал вызовы методов в качестве канонического примера, который иллюстрирует разницу между ранним и поздним связыванием. Теперь я понимаю вашу точку зрения; анализ, который точно определяет, как выполняется преобразование, также может быть выполнен во время выполнения или во время компиляции и, следовательно, в некотором смысле также является формой «позднего связывания» или «раннего связывания».

Давайте возьмем в качестве примера это преобразование:

int x = Whatever();
short y = (short)x;

Это явное преобразование полностью «связано» во время компиляции. Компилятор знает, что операндом является int, что целевой тип является коротким, что преобразование будет выполнено путем усечения четырехбайтового int до двухбайтового короткого. Преобразование, конечно, фактически выполняется во время выполнения.

Теперь давайте сделаем это немного менее понятным:

int x = Whatever();
short y = checked((short)x);

Явное преобразование снова связано во время компиляции. Мы знаем, как будет выполняться операция. Но мы также знаем, что во время выполнения будет проверяться значение int, чтобы убедиться, что оно соответствует короткому .

Считается ли это "поздним связыванием" в вашей книге? Часть анализа выполняется во время компиляции, но часть анализа выполняется во время выполнения.

Теперь давайте рассмотрим бокс:

int x = Whatever();
object q = x;

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

А как насчет распаковки?

int x = Whatever();
object q = x;
int y = (int)q;

Какой анализ выполняется во время компиляции? Все, что мы знаем во время компиляции, это то, что это конвертирование без распаковки. Фактическая проверка типов выполняется во время выполнения. Является ли это формой «позднего связывания», потому что проверка типа выполняется во время выполнения, по вашему определению позднего связывания?

Как насчет этого?

int x = Whatever();
object q = x;
int y = (short)q;

Это вызывает исключение во время выполнения. Во время компиляции мы знаем, что это конвертирование без распаковки. Во время выполнения мы не выполняем «позднюю привязку», чтобы сказать «эй, у меня есть int в штучной упаковке, позвольте мне выяснить, как преобразовать это в распакованный шорт». Скорее, мы говорим: «мы пытаемся распаковать int в short; выбросить исключение». В штучной упаковке T может быть распакован только на T или обнуляемый T.

То есть распаковка "рано или поздно"? Это рано связано в том смысле, что мы знаем во время компиляции, что это конвертирование без распаковки. Это поздний предел в том смысле, что мы делаем проверку типа во время выполнения. Это не поздний предел в том смысле, что во время выполнения мы не делаем повторный анализ типов, который был бы сделан для преобразования int-to-short во время компиляции.

Как насчет этого?

int x = Whatever();
object q = x;
int y = Convert.ToInt16(q);

или

int x = Whatever();
dynamic q = x;
int y = (int)q;

Теперь мы делаем выполняем весь этот анализ во время выполнения; в обоих случаях мы выполняем анализ типа q во время выполнения, определяем, что q является упакованным целым числом, и "позднее связывание" преобразования.

Это все ясно? Трудно ответить на ваш вопрос, потому что он немного расплывчат в отношении того, что именно вы подразумеваете под «поздним связыванием» конверсии. Какая часть анализа является для вас «обязательной»?

5 голосов
/ 07 декабря 2011

Бокс запекается в инструкции IL во время компиляции, если это то, что вы ищете.

Если вы попытаетесь распаковать в тип, отличный от исходного, будет сгенерировано исключение.Пример # 1 это просто происходит с боксом неявно (тип значения для ссылки на тип преобразования).Пример №2. Во время выполнения взорван недействительный актерский состав.

Не уверен, насколько рано или поздно появляется связывание.

4 голосов
/ 07 декабря 2011

Компилятор выдаст инструкции по боксу, которые вы сможете увидеть в IL.С кодом

int item = 10;
object obj = item;
item = (int)obj;

Вы скомпилируетесь в что-то вроде

IL_0000:  ldc.i4.s    0A 
IL_0002:  stloc.0     
IL_0003:  ldloc.0     
IL_0004:  box         System.Int32
IL_0009:  stloc.1     
IL_000A:  ldloc.1     
IL_000B:  unbox.any   System.Int32
IL_0010:  stloc.0     

Во второй версии это просто взорвется.Объект типа string нельзя привести к целому числу.

1 голос
/ 07 декабря 2011

C # компилирует инструкции, которые выполняются во время выполнения.

Бокс влечет за собой (немалые) затраты времени выполнения;упаковка и распаковка могут привести к ошибкам во время выполнения (как показывает ваш пример «int i = (int) o»).

«Позднее связывание» против «раннего связывания» подразумевает что-то «динамическое» (например, связывание во время выполнениянекоторого виртуального метода объекта).В этом случае бокс «исправлен».Так что, думаю, вы могли бы сказать, что это «раннее связывание».

...