Как дженерики устраняют или уменьшают потребность в боксировании?

#c# #.net #generics #boxing

#c# #.net #дженерики #боксирование

Вопрос:

Читая книгу Джона Шарпа VS 2010, там говорится, что дженерики позволяют устранить необходимость приведения, уменьшить боксирование типов значений — уменьшить? Я думал, что его удалили так же, как и кастинг? Кто-нибудь может объяснить, пожалуйста?

Ответ №1:

Это не полностью устраняет использование боксирования и приведения… это просто значительно уменьшает их. Иногда вы знаете о типах вещей больше, чем компилятор. Например, предположим, что вы подключили один и тот же обработчик событий к множеству кнопок. Совсем не лишено смысла использовать:

 public void HandleClickEvent(object sender, EventArgs e)
{
    // We know it will always be a button, and we want an exception if it's not
    Button button = (Button) sender;
    ...
}
  

Ну вот и все — кастинг не умер.

Аналогично, боксирование все еще происходит в ситуациях, когда вы не знаете точный тип во время компиляции и не можете выразить его обобщенно. Два наиболее очевидных примера этого:

  • Отражение (выборка значения свойства с помощью отражения даст вам object , бокс, если необходимо)
  • Динамическая типизация в C # 4:

     dynamic d = CreateDynamicObject();
    int x = d.Foo(); // The dynamic call would have to box if necessary,
                     // the conversion will unbox
      

Так что бокс тоже не умер.

Если вы только говорите о хранении значений в коллекциях, то верно, что боксирование и приведение теперь появляются в коде намного, намного реже, чем раньше. Но не все находится в коллекции, и дженерики полезны и за пределами коллекций.

Комментарии:

1. Спасибо, Джон, хотя я не настолько продвинут, чтобы понять, как первый пример (событие) относится к дженерикам :/

2. @Miria: Это не так, и в этом как раз суть: дженерики не обращаются к каждому месту, которое вы, возможно, захотите создать или упаковать / распаковать. Вот почему дженерики могут только уменьшить количество приведений / упаковок / распаковок, а не полностью устранить это.

3. О, тогда я, вероятно, спросил неправильно. Я подумал: правда ли, что при использовании дженериков (говоря только об универсальном коде) этот код не требует кастинга? И почему боксирование только сокращается?

Ответ №2:

Что помогло мне много лет назад разобраться с дженериками, так это рассмотреть возможность использования дженерика, когда:

Вы добавляете параметр к методу, который содержит информацию о типе

 public object Parse(string input, Type outputType) 
// replace by:
public T Parse<T>(string input)
  

Вы используете поле экземпляра, которое содержит информацию о типе:

 class Foo
{
    private Type _wrappedObjectType;
    private object _wrappedObject;
}
// replace by
class Foo<T>
{
    private T _wrappedObject;
}