Подтвердить что ты не робот

Бокс при использовании дженериков в С#

У меня есть следующий простой код С#:

private Stack<Person> m_stack = new Stack<Person>();

public void Add<T>(T obj)
  where T : Person
{
     m_stack.Push(obj);
}

Это приведет к следующему IL-коду:

  .method public hidebysig instance void 
          Add<(ConsoleApplication1.Person) T>(!!T obj) cil managed
  {
    // Code size       20 (0x14)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  ldfld      class [System]System.Collections.Generic.Stack`1<class ConsoleApplication1.Person> ConsoleApplication1.Pool::m_stack
    IL_0007:  ldarg.1
    IL_0008:  box        !!T
    IL_000d:  callvirt   instance void class [System]System.Collections.Generic.Stack`1<class ConsoleApplication1.Person>::Push(!0)
    IL_0012:  nop
    IL_0013:  ret
  } // end of method Pool::Add

Итак, мой вопрос: почему бокс? (IL_0008) Я могу понять downcasting или даже скомпилировать ошибку, но почему бокс (Person является ссылочным типом...)

Спасибо заранее!

4b9b3361

Ответ 1

Выдержка из раздела Ecma-335 III 4.1

Если типTok является ссылочным типом, команда box ничего не делает.

где typeTok - это!! T в вашем случае.

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

Ответ 2

Я считаю, что это ограничение общего метода, которое делает это с вами, но...

В любом случае вообще не требуется общий метод. Просто напишите его как:


public void Add(Person person)
{
    m_stack.Push(person);
}

Вы обнаружите, что IL упрощается и полностью избегает проблемы. Если вы ограничены определенным типом ссылки, вы можете просто использовать этот тип ссылки.

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