Во многих случаях директивы CIL сами по себе недостаточно описательны для того, чтобы полностью выразить определение заданного типа .NET Core или члена типа. С учетом этого факта многие директивы CIL могут сопровождаться разнообразными
.class может быть снабжена атрибутом public (для установления видимости типа), атрибутом extends (для явного указания базового класса типа) и атрибутом implements (для перечисления набора интерфейсов, поддерживаемых данным типом).На заметку!
Не путайте атрибут .NET Core (см. главу 17) и атрибут CIL, которые являются двумя совершенно разными понятиями.Роль кодов операций СIL
После того как сборка, пространство имен и набор типов .NET Core определены в терминах языка CIL с использованием различных директив и связанных атрибутов, остается только предоставить логику реализации для типов. Это работа
string применяется код операции, который вместо дружественного имени наподобие LoadString имеет имя ldstr.Справедливости ради следует отметить, что некоторые коды операций CIL довольно естественно отображаются на свои аналоги в C# (например, box
unbox, throw и sizeof). Вы увидите, что коды операций CIL всегда используются внутри области реализации члена и в отличие от директив никогда не записываются с префиксом-точкой.Разница между кодами операций и их мнемоническими эквивалентами в СIL
Как только что объяснялось, для реализации членов отдельно взятого типа применяются коды операций вроде ldstr
ldstr, являются FirstSamples:int Add(int x, int y)
{
return x + y;
}
В терминах CIL действие сложения двух чисел выражается посредством кода операции 0X58
0X59, а действие по размещению нового объекта в управляемой куче записывается с использованием кода операции 0X73. С учетом описанной реальности "код CIL" , обрабатываемый JIT-компилятором, представляет собой не более чем порцию двоичных данных.К счастью, для каждого двоичного кода операции CIL предусмотрен соответствующий мнемонический эквивалент. Например, вместо кода 0X58
add, вместо 0X59 — sub, а вместо 0X73 — newobj. С учетом такой разницы между кодами операций и их мнемоническими эквивалентами декомпиляторы CIL, подобные ildasm.exe, транслируют двоичные коды операций сборки в соответствующие им мнемонические эквиваленты CIL. Вот как ildasm.exe представит в CIL предыдущий метод Add(), написанный на языке C# (в зависимости от версии .NET Core вывод может отличаться):.method assembly hidebysig static int32 Add(int32 x,int32 y) cil managed
{
// Code size 9 (0x9)
.maxstack 2
.locals init ([0] int32 int32 V_0)
IL_0000: /* 00 | */ nop
IL_0001: /* 02 | */ ldarg.0
IL_0002: /* 03 | */ ldarg.1
IL_0003: /* 58 | */ add
IL_0004: /* 0A | */ stloc.0
IL_0005: /* 2B | 00 */ br.s IL_0007
IL_0007: /* 06 | */ ldloc.0
IL_0008: /* 2A | */ ret
} //end of method
Если вы не занимаетесь разработкой исключительно низкоуровневого программного обеспечения .NET Core (вроде специального управляемого компилятора), то иметь дело с числовыми двоичными кодами операций CIL никогда не придется. На практике когда программисты, использующие .NET Core, говорят о "кодах операций CIL", они имеют в виду набор дружественных строковых мнемонических эквивалентов (что и делается в настоящей книге), а не лежащие в основе числовые значения.
Заталкивание и выталкивание: основанная на стеке природа CIL