Почему! 0 - это тип языка Microsoft Intermediate Language (MSIL)?

89

Во многих списках MSIL я заметил следующее:

System.Nullable`1<!0> etc ...

или

class !0 etc ...

Что означает !0в этих обстоятельствах?

Драгно
источник

Ответы:

119

Это особенность декомпилятора, который вы используете для просмотра сборки .NET. Это поведение ildasm.exe, другие, такие как Reflector или ILSpy, понимают это правильно. Программист Microsoft, написавший это, взял ярлык, он генерирует строку из IL, которая просто отображает аргумент типа в том виде, в каком он закодирован, без написания дополнительного кода для поиска имени аргумента типа в метаданных.

Вам нужно читать !nкак аргумент n-го типа универсального типа. Где! 0 означает «аргумент первого типа»,! 1 означает «аргумент второго типа» и т.д. Для Nullable <> вы знаете, что '! 0` означает' T 'из статьи MSDN.

Вы также можете столкнуться с чем-то вроде !!T. Два восклицательных знака обозначают аргумент типа для универсального метода . На этот раз, ildasm.exe ли искать имя аргумента типа вместо использования !!0. Почему программист использовал ярлык для универсальных типов, а не для универсальных методов, трудно реконструировать. Ildasm - довольно необычная программа, написанная в стиле программирования C ++, который сильно отличается от другого кода C ++ в .NET. Не такие дисциплинированные, ненулевые шансы, что это задание стажера :)

Суффикс `1 в" Nullable "является нормальной кодировкой для имен универсальных типов, он указывает, что универсальный тип имеет один аргумент типа. Другими словами, для Nullable <> вы никогда не увидите, что используется! 1.

Так что просто читайте !0как "Т". Или воспользуйтесь декомпилятором получше.

Ганс Пассан
источник
35

Это параметр универсального типа.

Они позиционные.

Декомпилируйте некоторый общий код, чтобы увидеть, как они используются (сравните IL с C #).

леппи
источник
5
Если я использую TryRoslyn, я не понимаю ... goo.gl/ZZKE38 Я получаю, !Tи !!T, в зависимости от того, является ли общий параметр содержащим класс или метод ... То же самое, если я использую ildasm
xanatos
@xanatos Не всегда. Я также вижу код вроде ldfld class System.Collections.Generic.Dictionary``2<!0, !1> valuetype System.Collections.Generic.Dictionary``2/Enumerator<!TKey, !TValue>::dictionaryили call instance void class System.Collections.Generic.Dictionary``2<!TKey, !TValue>::Insert(!0, !1, bool). В любом случае необработанный IL использует только позиционный аргумент - !TKeyэто уже попытка сделать IL более читабельным. Может, не всегда получается? В спецификации ECMA всегда используется также позиционный !0/ !00.
Luaan