Por que! 0 é um tipo em Microsoft Intermediate Language (MSIL)?

88

Em muitas listagens MSIL, observei o seguinte:

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

ou

class !0 etc ...

Qual é o significado de !0nessas circunstâncias?

Dragno
fonte

Respostas:

118

Essa é uma peculiaridade do descompilador que você usa para examinar um assembly .NET. É o comportamento de ildasm.exe, outros como Reflector ou ILSpy acertam. O programador da Microsoft que o escreveu pegou um atalho, ele gera uma string a partir do IL que apenas exibe o argumento do tipo da forma como está codificado, sem escrever o código extra para pesquisar o nome do argumento do tipo nos metadados.

Você precisa ler !ncomo o enésimo argumento de tipo do tipo genérico. Onde! 0 significa "argumento de primeiro tipo",! 1 significa "argumento de segundo tipo", etc. Para Nullable <>, você sabe que '! 0` significa' T 'do artigo do MSDN.

Você também pode encontrar algo parecido !!T. Dois pontos de exclamação indicam um argumento de tipo para um método genérico . Desta vez, ildasm.exe não procurar o nome argumento de tipo em vez de usar !!0. Por que o programador pegou o atalho em tipos genéricos, mas não em métodos genéricos, é difícil de fazer engenharia reversa. Ildasm é um programa muito peculiar e foi escrito em um estilo de codificação C ++ muito diferente de outros códigos C ++ em .NET. Não tão disciplinado, probabilidade diferente de zero de que esta fosse uma tarefa de estagiário :)

O sufixo `1 em" Nullable "é uma codificação normal para nomes de tipo genérico, ele indica que o tipo genérico tem um argumento de tipo. Em outras palavras, para Nullable <> você nunca verá! 1 sendo usado.

Portanto, simplesmente leia !0como "T". Ou use um descompilador melhor.

Hans Passant
fonte
35

Esse é um parâmetro de tipo genérico.

Eles são posicionais.

Decompile algum código genérico para ver como eles são usados ​​(compare IL com C #).

leppie
fonte
5
Se eu usar TryRoslyn não entendo ... goo.gl/ZZKE38 entendo !Te !!T, dependendo se o parâmetro genérico é da classe que contém ou do método ... O mesmo se eu usar ildasm
xanatos
@xanatos Nem sempre. Também vejo código como ldfld class System.Collections.Generic.Dictionary``2<!0, !1> valuetype System.Collections.Generic.Dictionary``2/Enumerator<!TKey, !TValue>::dictionaryou call instance void class System.Collections.Generic.Dictionary``2<!TKey, !TValue>::Insert(!0, !1, bool). O IL bruto usa apenas o argumento posicional de qualquer maneira - o !TKeyjá é uma tentativa de tornar o IL mais legível. Talvez nem sempre funcione bem? A especificação ECMA sempre usa o posicional !0/ !00também.
Luaan de