Dlaczego! 0 jest typem w języku Microsoft Intermediate Language (MSIL)?

88

W wielu aukcjach MSIL zauważyłem, co następuje:

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

lub

class !0 etc ...

Jakie jest znaczenie !0w tych okolicznościach?

Dragno
źródło

Odpowiedzi:

118

To jest dziwactwo dekompilatora, którego używasz do oglądania zestawu .NET. Jest to zachowanie ildasm.exe, inne, takie jak Reflector lub ILSpy, robią to dobrze. Programista Microsoft, który to napisał, skorzystał ze skrótu, generuje ciąg z IL, który po prostu wyświetla argument typu w sposób, w jaki jest zakodowany, bez pisania dodatkowego kodu do wyszukiwania nazwy argumentu typu w metadanych.

Musisz odczytywać !njako n-ty argument typu ogólnego. Gdzie! 0 oznacza „argument pierwszego typu”,! 1 oznacza „argument drugiego typu” itd. W przypadku Nullable <> wiesz, że „! 0” oznacza „T” z artykułu MSDN.

Możesz również napotkać coś takiego !!T. Dwa wykrzykniki wskazują argument typu dla metody ogólnej . Tym razem ildasm.exe ma wyszukać nazwę argumentu typu zamiast używać !!0. Dlaczego programista wybrał skrót do typów ogólnych, ale nie do metod ogólnych, jest trudny do odtworzenia. Ildasm to dość dziwaczny program napisany w stylu C ++, który bardzo różni się od innych kodów C ++ w .NET. Nie tak zdyscyplinowane, niezerowe szanse, że to zadanie stażysty :)

Przyrostek `1 w polu„ Nullable ”jest normalnym kodowaniem dla nazw typów ogólnych, wskazuje, że typ ogólny ma jeden argument typu. Innymi słowy, dla Nullable <> nigdy nie zobaczysz! 1 używanego.

Więc po prostu czytaj !0jako „T”. Lub użyj lepszego dekompilatora.

Hans Passant
źródło
35

To jest parametr typu ogólnego.

Są pozycyjne.

Zdekompiluj kod ogólny, aby zobaczyć, jak są używane (porównaj IL z C #).

leppie
źródło
5
Jeśli używam TryRoslyn, nie rozumiem ... goo.gl/ZZKE38 otrzymuję !Ti !!T, w zależności od tego, czy parametr generyczny należy do klasy zawierającej, czy do metody ... To samo, jeśli używam ildasm
xanatos
@xanatos Nie zawsze. Widzę również kod taki jak ldfld class System.Collections.Generic.Dictionary``2<!0, !1> valuetype System.Collections.Generic.Dictionary``2/Enumerator<!TKey, !TValue>::dictionarylub call instance void class System.Collections.Generic.Dictionary``2<!TKey, !TValue>::Insert(!0, !1, bool). Surowy IL i tak używa tylko argumentu pozycyjnego - !TKeyjest to już próba uczynienia IL bardziej czytelną. Może nie zawsze działa dobrze? Specyfikacja ECMA zawsze używa również pozycji !0/ !00.
Luaan