Так что, если вы создадите тип Point (сейчас переопределенный, как класс) и захотите взаимодействовать с его членами, то должны записать следующий программный код (иначе возникнет ошибка компиляции).

unsafe public static void Main {

 point pt = new Point;

 pt.x = 5;

 pt.y = 6;

 // Фиксация pt, чтобы не допустить перемещения

 // или удаления при сборке мусора.

 fixed (int* p =&pt.x) {

  // Переменная int* используется здесь.

 }

 // Теперь pt не зафиксирована и может быть убрана

 // сборщиком мусора.

 Console.WriteLine("Значение Point: {0}", pt);

}

В сущности, ключевое слово fixed позволяет строить операторы, закрепляющие ссылочную переменную в памяти, чтобы ее адрес оставался постоянным на время выполнения оператора. Для гарантии безопасности обязательно фиксируйте ссылки при взаимодействии со ссылочными типами из небезопасного контекста программного кода.

<p>Ключевое слово sizeof</p>

В заключение обсуждения вопросов, связанных с небезопасным контекстом в C#, рассмотрим ключевое слово sizeof. Как и в C(++), ключевое слово C# sizeof используется для того, чтобы выяснить размер в байтах типа, характеризуемого значениями (но не ссылочного типа), и это ключевое слово может использоваться только в рамках небезопасного контекста. Очевидно, что указанная возможность может оказаться полезной при взаимодействии с неуправляемыми API, созданными на базе C. Использовать ее очень просто.

unsafe {

 Console.WriteLine("Длина short равна {0}.", sizeof(short));

 Console.WriteLine("Длина int равна {0}.", sizeof(int));

 Console.WriteLine("Длина long равна {0}.", sizeof(long));

}

Поскольку sizeof может оценить число байтов для любого элемента, производного от System.ValueType, можно получать размеры пользовательских структур. Допустим, мы определили следующую структуру.

struct MyValueType {

 public short s;

 public int i;

 public long l;

}

Тогда ее размеры можно выяснить так.

unsafe {

 Console.WriteLine("Длина short равна {0}.", sizeof(short));

 Console.WriteLine("Длина int равна {0}.", sizeof(int));

 Console.WriteLine("Длина long равна {0}.", sizeof(long));

 Console.WriteLine("Длина MyValueType равна {0}."/ sizeof(MyValueType));

}

Исходный код. Проект UnsafeCode размещен в подкаталоге, соответствующем главе 9.

<p>Директивы препроцессора C#</p>

Подобно многим другим языкам из семейства C, в C# поддерживаются различные символы, позволяющие влиять на процесс компиляции. Перед рассмотрением директив препроцессора C# согласуем соответствующую терминологию. Термин "директива препроцессора C#" не вполне точен. Фактически этот термин используется только для согласованности с языками программирования C и C++. В C# нет отдельного шага препроцессора. Директивы препроцессора в C# являются составной частью процесса лексического анализа компилятора.

Так или иначе, синтаксис директив препроцессора C# очень похож на синтаксис соответствующих директив остальных членов семейства C в том, что эти директивы всегда имеют префикс, обозначенный знаком "диез" (#). В табл. 9.4 описаны некоторые из наиболее часто используемых директив (подробности можно найти в документации .NET Framework 2.0 SDK).

Таблица 9.4. Типичные директивы препроцессора C#

Директивы Описание
#region, #endregion Используются для обозначения разделов стягиваемого исходного кода
#define, #undef Используются для определения и отмены определения символов условной компиляции
#if, #elif, #else, #endif Используются для условного пропуска разделов исходного кода (на основе указанных символов компиляции)
<p>Разделы программного кода</p>
Перейти на страницу:

Похожие книги