EDIT
Я сейчас сталкивался. Я сейчас сталкивался с https://msdn.microsoft.com/en-us/library/sbh15dya.aspx, в котором четко говорится, что генерики при использовании ссылочных типов повторно используют один и тот же код, поэтому я бы принял это как окончательный авторитет.
ОРИГИНАЛЬНЫЙ ОТВЕТ
Я вижу здесь два несогласных ответа, и у обоих есть ссылки на их сторону, поэтому я попытаюсь добавить свои два цента.
Во-первых, Clr via C # Джеффри Рихтера, опубликованный Microsoft Press, так же действителен, как и блог msdn, тем более, что блог уже устарел (для получения дополнительных книг смотрите «1015 ** 1016») что он эксперт по windows и .net).
Теперь позвольте мне сделать мой собственный анализ.
Очевидно, что два универсальных типа, которые содержат разные аргументы ссылочного типа, не могут использовать один и тот же код
Например, List и List > не могут совместно использовать один и тот же код, так как это приведет к возможности добавить объект TypeA в List с помощью отражения, и clr будет строго типизирован для генетики. также (в отличие от Java, в котором только компилятор проверяет generic, но базовая JVM не имеет понятия о них).
И это относится не только к типам, но и к методам, поскольку, например, универсальный метод типа T может создать объект типа T (например, ничто не мешает ему создать новый List ), в этом случае повторное использование одного и того же кода может привести к хаосу.
Кроме того, метод GetType не может быть переопределен, и он фактически всегда возвращает правильный универсальный тип, доказывая, что каждый аргумент типа действительно имеет свой собственный код.
(Этот пункт даже важнее, чем кажется, поскольку clr и jit работают на основе объекта типа, созданного для этого объекта, с помощью GetType (), что просто означает, что для каждого аргумента типа должен быть отдельный объект, даже для ссылочных типов )
Еще одна проблема, которая может возникнуть в результате повторного использования кода, поскольку операторы is и as больше не будут работать правильно, и в целом у всех типов приведения будут серьезные проблемы.
СЕЙЧАС ДЛЯ АКТУАЛЬНОЙ ТЕСТИРОВАНИЯ:
Я проверил его, имея универсальный тип, который содержал статический член, и затем создал два объекта с различными параметрами типа, и статические поля явно не были разделены, ясно доказывая, что код не является общим даже для ссылочных типов.
EDIT:
См. http://blogs.msdn.com/b/csharpfaq/archive/2004/03/12/how-do-c-generics-compare-to-c-templates.aspx о том, как это реализовано:
Использование пространства
Использование пробела в C ++ и C # различно. Потому что C ++
шаблоны создаются во время компиляции, каждое использование различного типа в
шаблон приводит к тому, что отдельный фрагмент кода создается
компилятор.
В мире C # все несколько иначе. Фактические реализации
с использованием определенного типа создаются во время выполнения. Когда среда выполнения создает
типа как List, JIT увидит, если это уже было
создано. Если это так, он просто использует этот код. Если нет, это займет
IL, который сгенерировал компилятор и делает соответствующие замены
с фактическим типом.
Это не совсем правильно. Существует отдельный собственный путь к коду
каждый тип значения, но так как все ссылочные типы имеют размер ссылки,
они могут поделиться своей реализацией.
Это означает, что подход C # должен иметь меньшую площадь
диск, и в памяти, так что это преимущество для дженериков по сравнению с C ++
шаблоны.
Фактически, компоновщик C ++ реализует функцию, известную как «шаблон».
сворачивание », где компоновщик ищет разделы собственного кода, которые
идентичны, и если он их находит, складывает их вместе. Так что это не
четкий, как это может показаться.
Как можно видеть, CLR «может» повторно использовать реализацию для ссылочных типов, как это делают текущие компиляторы c ++, однако на это нет никаких гарантий, и для небезопасного кода, использующего stackalloc и указатели, это, вероятно, не так, и могут быть и другие ситуации.
Однако мы должны знать, что в системе типов CLR они обрабатываются как разные типы, такие как разные вызовы статических конструкторов, отдельные статические поля, отдельные объекты типа и объект с аргументом типа T1, не должны быть в состоянии получить доступ к приватному полю другого объекта с аргументом типа T2 (хотя для объекта того же типа действительно возможно получить доступ к приватным полям из другого объекта того же типа).