Эндрю Троелсен - ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
- Название:ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2007
- Город:Москва • Санкт-Петербург • Киев
- ISBN:ISBN 5-8459-1124-9
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Эндрю Троелсен - ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание краткое содержание
В этой книге содержится описание базовых принципов функционирования платформы .NET, системы типов .NET и различных инструментальных средств разработки, используемых при создании приложений .NET. Представлены базовые возможности языка программирования C# 2005, включая новые синтаксические конструкции, появившиеся с выходом .NET 2.0, а также синтаксис и семантика языка CIL. В книге рассматривается формат сборок .NET, библиотеки базовых классов .NET. файловый ввод-вывод, возможности удаленного доступа, конструкция приложений Windows Forms, доступ к базам данных с помощью ADO.NET, создание Web-приложений ASP.NET и Web-служб XML. Книга содержит множество примеров программного кода, призванного помочь читателю в освоении предлагаемого материала. Программный код примеров можно загрузить с Web-сайта издательства.
ЯЗЫК ПРОГРАММИРОВАНИЯ С# 2005 И ПЛАТФОРМА .NET 2.0. 3-е издание - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Таблица 15.7. Коды операций для извлечения данных из cтека
Код операции | Описание |
---|---|
pop | Удаляет значение, находящееся в настоящий момент на вершине стека, но не обеспечивает сохранение этого значения |
starg | Сохраняет значение из вершины стека в аргументе метода с указанным индексом |
stloc (c множеством вариаций) | Удаляет значение, находящееся на вершине стека, и запоминает это значение в переменной с указанным индексом из списка локальных переменных |
stobj | Копирует значение указанного типа из стека в память по указанному адресу |
stsfld | Заменяет значение статического поля значением из cтека |
Следует также знать о том, что различные коды операций CIL при выполнении своих задач неявно удаляют значения из стека. Например, при вычитании одного числа из другого с помощью операции sub следует учитывать то, что прежде чем выполнить соответствующее вычисление, sub "вытолкнет" из стека два доступных значения. После выполнения операции в стек добавляется результат (как неожиданно!).
Директива .maxstack
При реализации метода непосредственно средствами CIL нужно помнить о специальной директиве, которая называется .maxstack. Как следует из ее названия, директива .maxstack задает максимальное число переменных, которые может вместить стек в любой момент времени при выполнении метода. К счастью, директива .maxstack имеет значение по умолчанию (8), которого оказывается достаточно для подавляющего большинства методов, создаваемых разработчиками. Но у вас также есть возможность определить это значение явно, чтобы при желании вручную указать числа локальных переменных в стеке.
.method public hidebysig instanсе void Speak() cil managed {
// В контексте этого метода в стек помещается ровно
// одно значение (строковый литерал).
.maxstack 1
ldstr "Всем привет…"
call void [mscorlib]System.Consolr::WriteLine(string)
ret
}
Объявление локальных переменных
Давайте выясним, как объявляются локальные переменные. Предположим, что мы должны построить в терминах CIL метод MyLocalVariables(), не имеющий никаких аргументов и возвращающий void. В этом методе мы должны определить три локальные переменные типов System.String, System.Int32 и System.Object. В C# соответствующий программный код мог бы выглядеть так, как показано ниже (напомним, что локальные переменные не получают значения по умолчанию, поэтому им перед использованием необходимо присвоить начальные значения).
public static void MyLocalVariables() {
string myStr = "CIL me dude…";
int myInt = 33;
object myObj = new object();
}
Если создавать MyLocalVariables() непосредственно в CIL, можно было бы написать следующее,
.method public hidebysig static void MyLocalVariables() cil managed {
.maxstack 6
// Определение трех локальных переданных.
.locals init( [0]string myStr, [1]int32 myInt, [2]object myObj)
// Загрузка строки в виртуальный стек выполнения.
ldstr "CIL me dude…"
// Извлечение текущего значения и сохранение его
// в локальной переменной [0].
stloc. 0
// Загрузка константы типа 'i4'
// (сокращение для int32) со значением 33.
ldc.i4 33
// Извлечение текущего значения и сохранение его
// в локальной переменной [1].
stloc. 1
// Создание нового объекта и помещение его в стек.
newobj instance void [mscorlib]System.Object::.ctor()
// Извлечение текущего значения и сохранение его
// в локальной переменной [2].
stloc. 2
ret
}
Как видите, в CIL при размещении локальных переменных сначала используется директива .locals с атрибутом init. При этом в скобках каждая переменная связывается со своим числовым индексом (здесь это [0], [1] и [2]). Каждый индекс идентифицируется типом данных и (необязательно) именем переменной. После определения локальных переменных соответствующее значение загружается в стек (с помощью подходящих кодов операций, связанных с загрузкой) и запоминается в локальной переменной (с помощью подходящих кодов операций для сохранения значений).
Связывание параметров с локальными переменными
Вы только что видели, как в CIL с помощью .local init объявляются локальные переменные, однако нужно еще выяснить, как передать отступающие параметры локальным методом. Рассмотрим следующий статический метод C#.
public staticint Add(int a , int b) {
return a + b;
}
Этот внешне "невинный" метод в терминах CIL существенно более "многословен". Во-первых, поступающие аргументы (а и b) следует поместить в виртуальный стек выполнение с помощью кода операций ldarg (загрузка аргумента). Затем используется код операции add, чтобы извлечь два значения из стека, найти сумму и снова сохранить значение в стеке. Наконец, эта сумма извлекается из стена и возвращается вызывающей стороне с помощью кода операции ret. Если дизассемблировать указанный метод C# с помощью ildasm.exe, вы обнаружите, что компилятор csc.exe добавляет множество дополнительных лексем, хотя сущность CIL-кода оказывается исключительно простой.
.method public hidebysig static int32 Add(int32 a, int32 b) cil managed {
.maxstack 2
ldarg.0// Загрузка 'a' в стек,
ldarg.1// Загрузка 'b' стек,
add// Сложение этих значений.
ret
}
Скрытая ссылка this
Обратите внимание на то, что в рамках программного кода CIL для ссылок на два входных аргумента (а и b) используются их индексы позиции (индекс 0 и индекс 1, поскольку индексация в виртуальном стеке выполнения начинается с нуля).
При анализе программного кода и его создании непосредственно в CIL следует быть очень внимательным, поскольку каждый (нестатический) метод, имеющий входные аргументы, автоматически получает неявный дополнительный параметр, который является ссылкой на текущий объект (это должно вызвать аналогию с ключевым словом C# this). Поэтому, если определить метод Add(), как нестатический
// Уже не является статическим!
public int Add(int a, int b) {
return a + b;
}
то входные аргументы а и b будут загружаться с помощью ldarg.1 и ldarg.2 (а не с помощью ожидаемых ldarg.0 и ldarg.1). Причина как раз в том, что ячейка 0 будет содержать неявную ссылку this. Рассмотрите следующий псевдокод.
// Это только псевдокод!
.method public hidebysig static int32 AddTwoIntParams( MyClass_HiddenThisPointer this,int32 a, int32 b) cil managed {
ldarg.0 // Загрузка MyClass_HiddenThisPointerв стек,
Интервал:
Закладка: