Язык программирования C#9 и платформа .NET5
Перед погружением в детали следует еще раз подчеркнуть, что вам очень редко, если вообще когда-нибудь, понадобится использовать типы указателей. Хотя C# позволяет опуститься на уровень манипуляций указателями, помните, что исполняющая среда .NET Core не имеет абсолютно никакого понятия о ваших намерениях. Соответственно, если вы неправильно управляете указателем, то сами и будете отвечать за последствия. С учетом этих предупреждений возникает вопрос: когда в принципе может возникнуть необходимость работы с типами указателей? Существуют две распространенные ситуации.
• Нужно оптимизировать избранные части приложения, напрямую манипулируя памятью за рамками ее управления со стороны исполняющей среды .NET 5.
• Необходимо вызывать методы из DLL-библиотеки, написанной на С, либо из сервера СОМ, которые требуют передачи типов указателей в качестве параметров. Но даже в таком случае часто можно обойтись без применения типов указателей, отдав предпочтение типу
и членам типаSystem.IntPtr.System.Runtime.InteropServices.MarshalЕсли вы решили задействовать данное средство языка С#, тогда придется информировать компилятор C# о своих намерениях, разрешив проекту поддерживать "небезопасный код". Создайте новый проект консольного приложения по имени
и включите поддержку небезопасного кода, добавив в файлUnsafeCodeследующие строки:UnsafeCode.csproj<PropertyGroup><AllowUnsafeBlocks>true</AllowUnsafeBlocks></PropertyGroup>Для установки этого свойства в Visual Studio предлагается графический пользовательский интерфейс. Откройте окно свойств проекта. В раскрывающемся списке Configuration (Конфигурация) выберите вариант All Configurations (Все конфигурации), перейдите на вкладку Build (Сборка) и отметьте флажок Allow unsafe code (Разрешить небезопасный код), как показано на рис. 11.1.
Ключевое слово unsafe
Для работы с указателями в C# должен быть специально объявлен блок "небезопасного кода" с использованием ключевого слова
(любой код, который не помечен ключевым словомunsafe, автоматически считается "безопасным"). Например, в следующем файлеunsafeобъявляется область небезопасного кода внутри операторов верхнего уровня:Program.csusing System;using UnsafeCode;Console.WriteLine("***** Calling method with unsafe code *****");unsafe{// Здесь работаем с указателями!}// Здесь работа с указателями невозможна!В дополнение к объявлению области небезопасного кода внутри метода можно строить "небезопасные" структуры, классы, члены типов и параметры. Ниже приведено несколько примеров (типы
иNodeв текущем проекте определять не нужно):Node2// Эта структура целиком является небезопасной и может// использоваться только в небезопасном контексте.unsafe struct Node{public int Value;public Node* Left;public Node* Right;}// Эта структура безопасна, но члены Node2* - нет.// Формально извне небезопасного контекста можно// обращаться к Value, но не к Left и Right.public struct Node2{public int Value;// Эти члены доступны только в небезопасном контексте!public unsafe Node2* Left;public unsafe Node2* Right;}Методы (статические либо уровня экземпляра) также могут быть помечены как небезопасные. Предположим, что какой-то статический метод будет использовать логику указателей. Чтобы обеспечить возможность вызова данного метода только из небезопасного контекста, его можно определить так:
static <b>unsafe</b> void SquareIntPointer(int* myIntPointer){// Возвести значение в квадрат просто для тестирования.*myIntPointer *= *myIntPointer;}Конфигурация метода требует, чтобы вызывающий код обращался к методу
следующим образом:SquareIntPointer()unsafe{int myInt = 10;<b> // Нормально, мы находимся в небезопасном контексте.</b>SquareIntPointer(&myInt);Console.WriteLine("myInt: {0}", myInt);}int myInt2 = 5;<b>// Ошибка на этапе компиляции!</b><b>// Это должно делаться в небезопасном контексте!</b>SquareIntPointer(&myInt2);Console.WriteLine("myInt: {0}", myInt2);Если вы не хотите вынуждать вызывающий код помещать такой вызов внутрь небезопасного контекста, то можете поместить все операторы верхнего уровня в блок
. При использовании в качестве точки входа методаunsafeможете пометитьMain()ключевым словомMain(). В таком случае приведенный ниже код скомпилируется:unsafe

