Em muitas listagens MSIL, observei o seguinte:
System.Nullable`1<!0> etc ...
ou
class !0 etc ...
Qual é o significado de !0
nessas circunstâncias?
Respostas:
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 !n
como 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 !0
como "T". Ou use um descompilador melhor.
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 #).
ldfld class System.Collections.Generic.Dictionary``2<!0, !1> valuetype System.Collections.Generic.Dictionary``2/Enumerator<!TKey, !TValue>::dictionary
ou 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 !TKey
já é uma tentativa de tornar o IL mais legível. Talvez nem sempre funcione bem? A especificação ECMA sempre usa o posicional !0
/ !00
também.
!T
e!!T
, dependendo se o parâmetro genérico é da classe que contém ou do método ... O mesmo se eu usar ildasm