Устранение ошибок и предупреждений в небезопасных конструкциях кода

В этой статье рассматривается следующая диагностика компилятора:

  • CS0193: оператор * или -> должен применяться к указателю
  • CS0196: указатель должен индексироваться только одним значением.
  • CS0208: невозможно взять адрес, получить размер или объявить указатель на управляемый тип ('type')
  • CS0209: тип локальной переменной, объявленной в операторе fixed, должен быть указателем
  • CS0210: необходимо предоставить инициализатор в объявлении или fixed оператореusing.
  • CS0211: невозможно принять адрес заданного выражения
  • CS0212: можно использовать только адрес нефиксированного выражения внутри инициализатора fixed инструкции.
  • CS0213: нельзя использовать инструкцию fixed для получения адреса выражения, которое уже было фиксировано.
  • CS0214: указатели и буферы фиксированного размера могут использоваться только в небезопасном контексте.
  • CS0227: небезопасный код может отображаться только в том случае, если компиляция с помощью /unsafe
  • CS0233: "идентификатор" не имеет предопределенного размера, поэтому sizeof может использоваться только в небезопасном контексте.
  • CS0242: эта операция не определена в указателях void
  • CS0244: Ни 'is' ни 'as' недопустимы для указанных типов указателей
  • CS0254: правая сторона назначения фиксированной инструкции может не быть выражением приведения
  • CS0459: не удается принять адрес локальной переменной только для чтения
  • CS0821: неявно типизированные локальные переменные не могут быть исправлены
  • CS1641: поле буфера фиксированного размера должно иметь описатель размера массива после имени поля
  • CS1642: поля буфера фиксированного размера могут быть только членами структур
  • CS1656: Невозможно присвоить значение переменной, потому что она является типом переменной только для чтения.
  • CS1663: тип буфера фиксированного размера должен быть одним из следующих типов: bool, byteили shortintlongcharsbyteushortuintulongfloatdouble
  • CS1664: буфер фиксированного размера длиной 'length' и типа 'type' слишком велик
  • CS1665: буферы фиксированного размера должны иметь длину больше нуля
  • CS1666: нельзя использовать буферы фиксированного размера, содержащиеся в нефиксированных выражениях. Попробуйте использовать фиксированную инструкцию.
  • CS1708: доступ к буферам фиксированного размера можно получить только через локальные или поля
  • CS1716: не используйте атрибут 'System.Runtime.CompilerServices.FixedBuffer' . Вместо этого используйте модификатор поля fixed.
  • CS1919: небезопасный тип "имя типа" нельзя использовать в создании объекта
  • CS4004: невозможно await в небезопасном контексте
  • CS7092: фиксированный буфер может иметь только одно измерение.
  • CS8372: не используйте атрибут 'System.Runtime.CompilerServices.FixedBuffer' в свойстве
  • CS8385: данное выражение нельзя использовать в фиксированной инструкции
  • CS8500: это принимает адрес, получает размер или объявляет указатель на управляемый тип ('type')
  • CS8812: не удается преобразовать группу методов "method" в тип указателя без функции "type".
  • CS9049: фиксированное поле не должно быть полем ссылок.
  • CS9123: оператор '&' не должен использоваться для параметров или локальных переменных в асинхронных методах.
  • CS9360: эта операция может использоваться только в небезопасном контексте.
  • CS9361: stackalloc выражение без инициализатора внутри SkipLocalsInit может использоваться только в небезопасном контексте.
  • CS9362: "member" должен использоваться в небезопасном контексте, так как он помечен как "unsafe"
  • CS9363: "member" должен использоваться в небезопасном контексте, так как он имеет указатели в подписи.
  • CS9364: небезопасный элемент «element» не может переопределить безопасный элемент «element»
  • CS9365: небезопасный член "член" не может неявно реализовать безопасный член "член"
  • CS9366: Небезопасный элемент "член" не может реализовать безопасный элемент "член"
  • CS9367: RequiresUnsafeAttribute нельзя применить к этому символу.
  • CS9368: RequiresUnsafeAttribute действителен только в соответствии с обновленными правилами безопасности памяти.
  • CS9376: Для конструктора "constructor", помеченного как "unsafe", требуется небезопасный контекст, чтобы удовлетворить ограничению "new()" для параметра типа "type parameter" в "generic type or method".
  • CS9377: модификатор 'unsafe' не имеет никакого эффекта в соответствии с текущими правилами безопасности памяти.
  • CS9379: не используйте "RequiresUnsafeAttribute" в источнике; используйте вместо него модификатор "unsafe".
  • CS9388: модификатор 'safe' может использоваться только для элементов,extern которые не помечены как 'unsafe'.
  • CS9389: Член 'extern' должен быть помечен как 'unsafe' или 'safe'.
  • CS9390: Оба частичных объявления члена должны быть помечены "safe", либо ни одно из них не должно быть помечено "safe"
  • CS9392: поле в явном или расширенном типе макета должно быть отмечено как "unsafe" или "safe".
  • CS9396: Не удается указать модификаторы 'unsafe' или 'safe' как для свойства или индексатора 'property', так и для его аксессора. Удалите один из них.
  • CS9397: Не удается указать один и тот же модификатор "unsafe" или "safe" для всех аксессоров свойства или индексатора "property". Вместо этого укажите этот модификатор для самого свойства.
  • CS9398: Невозможно использовать await в операторе 'fixed'

Операции указателя и отмена ссылок

  • CS0193: оператор *-> должен применяться к указателю
  • CS0196: указатель должен индексироваться только одним значением.
  • CS0242: эта операция не определена в указателях void

Чтобы правильно использовать операции указателя, следуйте правилам разыменования, индексации и арифметическим операциям. Дополнительные сведения см. в разделе "Типы указателей " и указатели функций.

  • * -> Примените оператор только к указателям данных (CS0193). Не используйте эти операторы с неуказательными типами или указателями на функции. В отличие от C/C++, в C# невозможно разыменовать указатели функций.
  • Указатели индекса только с одним значением (CS0196). Указатели не поддерживают многомерное индексирование.
  • Избегайте операций, которые не определены в указателях void (CS0242). Не инкрементируйте указатель void, так как компилятор не знает размер данных, на которые он указывает.

Типы указателей и управляемые типы

  • CS0208: нельзя взять адрес, узнать размер или объявить указатель на управляемый тип ('тип')
  • CS0233: "идентификатор" не имеет предопределенного размера, поэтому sizeof может использоваться только в небезопасном контексте.
  • CS8500: это принимает адрес, получает размер или объявляет указатель на управляемый тип ('type')

Чтобы работать с указателями и sizeof оператором правильно, используйте неуправляемые типы и правильные контексты. Дополнительные сведения см. в разделе "Неуправляемые типы" и о операторе sizeof.

  • Используйте указатели только с неуправляемыми типами (CS0208). Не объявляйте указатели, не берите адрес и размер управляемых типов. Управляемые типы включают ссылочные типы и структуры, содержащие поля ссылочного типа или свойства.
  • sizeof Используйте оператор в контексте unsafe при работе с типами, размер которых не является константой времени компиляции (CS0233).
  • Избегайте использования адреса, получения размера или объявления указателя на управляемый тип (CS8500). Это предупреждение (уровень 4) выдаётся, когда компилятор обнаруживает операции с указателями над управляемыми типами. Управляемый тип — это любой ссылочный тип или любая структура, содержащая ссылочный тип в качестве поля или свойства. Дополнительные сведения см. в разделе "Неуправляемые типы".

Фиксированное использование инструкций

  • CS0209: тип локальной переменной, объявленной в операторе fixed, должен быть типом указателя.
  • CS0210: в объявлении инструкции fixed или using необходимо предоставить инициализатор.
  • CS0211: невозможно принять адрес заданного выражения
  • CS0212: можно использовать только адрес нефиксированного выражения внутри инициализатора фиксированной инструкции.
  • CS0213: нельзя использовать оператор fixed для получения адреса уже фиксированного выражения.
  • CS0254: правая сторона назначения фиксированной инструкции может не быть выражением приведения
  • CS0459: не удается принять адрес локальной переменной только для чтения
  • CS0821: неявно типизированные локальные переменные не могут быть исправлены
  • CS1656: Невозможно присвоить значение переменной, поскольку она имеет тип "только для чтения".
  • CS8385: данное выражение нельзя использовать в фиксированной инструкции

Эти ошибки возникают при неправильном использовании инструкцииfixed. Инструкция fixed предотвращает сборщик мусора от перемещения переменной, которую можно перемещать, и объявляет указатель на эту переменную. Дополнительные сведения см. в разделе "Небезопасный код и указатели".

Чтобы правильно использовать инструкцию fixed , выполните следующие действия.

  • Объявите переменную как тип указателя (CS0209).
  • Укажите инициализатор в объявлении инструкции fixed (CS0210).
  • Используйте адрес только допустимых выражений: поля, локальные переменные и разыменование указателя (CS0211). Не используйте адрес вычисляемых выражений, таких как сумма двух переменных.
  • Используйте оператор address-of для нефиксированных выражений только в инициализаторе fixed инструкции (CS0212).
  • Не используйте инструкцию fixed для уже фиксированных выражений (CS0213). Локальные переменные и параметры в unsafe методе уже расположены на стеке.
  • Не используйте выражения приведения на правой стороне выражения присваивания fixed (CS0254).
  • Не считывайте адрес локальных переменных, которые являются только для чтения (CS0459). Переменные в foreach циклах, using инструкциях и fixed инструкциях доступны только для чтения. Эта ошибка больше не создается текущими версиями компилятора.
  • Используйте явные типы вместо var в инструкциях fixed (CS0821).
  • Не присваивайте переменным в контекстах, доступных только для чтения, таких как foreach циклы, using инструкции или fixed инструкции (CS1656).
  • Используйте только выражения, допускающие закрепление в операторе fixed (CS8385). Выражение должно быть адресной переменной, строкой или типом, реализующим подходящий GetPinnableReference метод.

Небезопасные требования к контексту

  • CS0214: указатели и буферы фиксированного размера могут использоваться только в небезопасном контексте.
  • CS0227: небезопасный код может использоваться только при компиляции с параметром /unsafe
  • CS0244: ни 'is', ни 'as' не являются допустимыми для типов указателей
  • CS1919: небезопасный тип "имя типа" нельзя использовать в создании объекта
  • CS4004: невозможно await в небезопасном контексте
  • CS9123: оператор '&' не должен использоваться для параметров или локальных переменных в асинхронных методах
  • CS9360: эта операция может использоваться только в небезопасном контексте.
  • CS9361: stackalloc выражение без инициализатора внутри SkipLocalsInit может использоваться только в небезопасном контексте.
  • CS9362: "member" должен использоваться в небезопасном контексте, так как он помечен как "unsafe"
  • CS9363: "member" должен использоваться в небезопасном контексте, так как он имеет указатели в подписи.
  • CS9376: Для конструктора "constructor", помеченного как "unsafe", требуется небезопасный контекст, чтобы удовлетворить ограничению "new()" для параметра типа "type parameter" в "generic type or method"
  • CS9398: Невозможно использовать await в контексте оператора 'fixed'

Диагностика выполняется при использовании небезопасных конструкций кода без требуемого контекста unsafe, или при попытке выполнить операции, которые запрещены с небезопасными типами. Дополнительные сведения см. в разделе "Небезопасный код и указатели" иключевоеunsafe слово.

  • Пометьте методы, типы или блоки кода, использующие указатели или буферы фиксированного размера с unsafe ключевым словом (CS0214). Компилятору требуется явный небезопасный контекст для любого кода, который работает с типами указателей или полями буфера фиксированного размера.
  • Включите параметр компилятора AllowUnsafeBlocks в параметрах проекта (CS0227). Без этого параметра компилятор отклоняет все unsafe блоки, даже если код является правильным.
  • Не используйте is или as операторы с типами указателей (CS0244). Эти операторы тестирования типов недопустимы для указателей, так как указатели не участвуют в иерархии типов.
  • Не используйте new оператор для создания экземпляров типов указателя (CS1919). Чтобы создать объекты в неуправляемой памяти, используйте взаимодействие для вызова собственных методов, возвращающих указатели.
  • Рассматривайте CS4004 как устаревшие рекомендации. В C# 14 и более ранних версиях использование await внутри небезопасного контекста не допускается. Согласно изменениям в области безопасности памяти в предварительной версии C# 15, await допускается в небезопасном контексте, поэтому это общее ограничение больше не соответствует текущему правилу.
  • Не используйте оператор адреса (&) для параметров или локальных переменных в асинхронных методах (CS9123). Переменная может не существовать в стеке, когда асинхронная операция возобновляется после точки приостановки.
  • Помечайте операции, включающие небезопасные конструкции (например, разыменование указателя, взятие адреса или sizeof на неуправляемых типах) с помощью ключевого слова unsafe (CS9360). В соответствии с обновленными правилами безопасности памяти C# 15 компилятор определяет отдельные операции, требующие небезопасного контекста.
  • Используйте ключевое unsafe слово для stackalloc выражений без инициализаторов, когда применён атрибут SkipLocalsInit (CS9361). Без инициализатора выделенная стеком память содержит неинициализированные данные, которые являются небезопасной операцией.
  • unsafe Используйте контекст при вызове участников unsafe (CS9362) или членов с указателями в подписях (CS9363). Согласно обновлённой модели безопасности памяти компилятор сообщает об ошибке CS9362 для элементов, которые явно перекладывают обязательство по обеспечению безопасности на вызывающую сторону, и об ошибке CS9363 для устаревших случаев совместимости, когда сама сигнатура содержит указатели.
  • Используйте контекст unsafe, когда ограничение new() требует вызова конструктора, помеченного как unsafe (CS9376). Обобщённый экземпляр вызывает конструктор неявно, поэтому вызов должен происходить в небезопасном контексте.
  • Переместите await за пределы тела или инициализатора инструкции fixed (CS9398). Предварительная версия C# 15 разрешает fixed в небезопасном контексте, но время жизни закрепления в инструкции await по-прежнему не может охватывать точку приостановки асинхронной операции. Дождитесь завершения операции перед входом в fixed, или выйдите из инструкции fixed перед ожиданием.

Небезопасные контракты безопасности членов

  • CS9364: небезопасный элемент "member" не может переопределить безопасный элемент "member"
  • CS9365: небезопасный член "member" не может неявно реализовать безопасный член "member"
  • CS9366: небезопасный член "член" не может реализовать безопасный член "член"
  • CS9367: RequiresUnsafeAttribute нельзя применить к этому символу.
  • CS9368: RequiresUnsafeAttribute действителен только в соответствии с обновленными правилами безопасности памяти.
  • CS9377: модификатор 'unsafe' не имеет никакого эффекта в соответствии с текущими правилами безопасности памяти.
  • CS9379: не используйте "RequiresUnsafeAttribute" в источнике; используйте вместо него модификатор "unsafe".
  • CS9388: модификатор 'safe' может использоваться только для элементов,extern которые не помечены как 'unsafe'.
  • CS9389: элемент 'extern' должен быть помечен как 'unsafe' или 'safe'.
  • CS9390: оба частичных объявления члена должны быть помечены как "safe", либо ни одно не может быть помечено как "safe"
  • CS9396: Невозможно указать модификаторы "unsafe" или "safe" как для свойства или индексатора "property", так и для его аксессора. Удалите один из них.
  • CS9397: Невозможно указать один и тот же модификатор "unsafe" или "safe" для всех аксессоров свойства или индексатора "property". Вместо этого укажите этот модификатор для самого свойства.

Эти средства диагностики применяют правила контракта безопасности C# 15 для членов, помеченных как небезопасные. Компилятор гарантирует, что небезопасные члены не нарушают ожидания безопасности, установленные базовыми классами и интерфейсами. Дополнительные сведения см. в разделе "Небезопасный код и указатели" иключевоеunsafe слово.

  • Не переопределите безопасный базовый элемент с небезопасным членом (CS9364). Переопределение должно сохранить безопасность контракта базового члена. Если базовый элемент является безопасным, переопределение также должно быть безопасным. Удалите модификатор unsafe или RequiresUnsafeAttribute из переопределяющего элемента, или пометьте базовый элемент как небезопасный.
  • Не реализуйте неявно безопасный элемент интерфейса с использованием небезопасного члена (CS9365). Если тип неявно реализует член интерфейса, вызывающие через интерфейс ожидают безопасной операции. Удалите небезопасное обозначение из реализуемого элемента или используйте явную реализацию интерфейса.
  • Не реализуйте явным образом безопасный элемент интерфейса с небезопасным членом (CS9366). Даже с явной реализацией необходимо сохранить контракт безопасности члена интерфейса.
  • Применяется RequiresUnsafeAttribute только к поддерживаемым типам символов (CS9367). Этот атрибут можно применять к методам, свойствам, событиям, конструкторам и типам, но не ко всем типам символов.
  • Включите обновленные правила безопасности памяти для использования RequiresUnsafeAttribute (CS9368). Этот атрибут является частью модели безопасности памяти C# 15 и не распознается в соответствии с устаревшими правилами. Убедитесь, что проект предназначен для языковой версии, поддерживающей обновленные правила.
  • unsafe Удалите модификатор, если он не имеет эффекта (CS9377). В соответствии с текущими правилами безопасности памяти в определенных контекстах не требуется использование модификатора unsafe. Компилятор предупреждает, когда модификатор не имеет смысла, чтобы можно было очистить ненужные заметки.
  • unsafe Используйте модификатор непосредственно в объявлении члена вместо применения RequiresUnsafeAttribute в исходном коде (CS9379). Атрибут предназначен только для представления метаданных; в исходном коде unsafe ключевое слово является правильным механизмом.
  • safe Примените модификатор только к extern элементам, которые еще не помечены unsafe (CS9388). Модификатор safe явно выбирает экстерн-член из небезопасного предположения по умолчанию для объявлений экстерна.
  • Пометьте каждый extern член как unsafe или safe (CS9389). В соответствии с обновленными правилами безопасности памяти экстерн-члены должны явно объявить свой контракт безопасности, так как компилятор не может проверить реализацию.
  • Убедитесь, что оба частичных объявления членов согласуются с модификатором safe (CS9390). Если одно частичное объявление отмечено safe, другой также должен быть помечен safe для поддержания согласованного контракта безопасности.
  • Поместите unsafe или safe либо на свойство или индексатор, либо на метод доступа, но не одновременно (CS9396). Если свойство задает контракт для всех методов доступа, поместите модификатор на само свойство. Если только один метод доступа отличается, поместите модификатор на этот метод доступа и оставьте свойство не измененным.
  • Если все методы доступа свойства или индексатора имеют один и тот же модификатор unsafe или safe, переместите этот модификатор в объявление свойства или индексатора (CS9397). Используйте модификаторы методов доступа только в том случае, если методы доступа намеренно различаются.

Явные или расширенные поля разметки

  • CS9392: поле в явном или расширенном типе макета должно быть отмечено как "unsafe" или "safe".

Это диагностическое сообщение возникает в обновлённой модели безопасности памяти, когда поле экземпляра используется в явном или расширенном размещении, а в объявлении не указано, является ли это поле unsafe или safe. Дополнительные сведения см. в разделе "Небезопасный код и указатели" иключевоеsafe слово.

  • Пометьте каждое поле экземпляра в типе с помощью [StructLayout(LayoutKind.Explicit)] или unsafe как [ExtendedLayout] или safe (CS9392). Если поле синтезируется для автоматического свойства, свойства с резервным полем, параметра первичного конструктора или полеподобного события, укажите модификатор для свойства, параметра или события, для которого создаётся это сгенерированное поле.

Буферы фиксированного размера

  • CS1641: поле буфера фиксированного размера должно иметь описатель размера массива после имени поля
  • CS1642: поля буфера фиксированного размера могут быть только членами структур
  • CS1663: тип буфера фиксированного размера должен быть одним из следующих типов: bool, byteили shortintlongcharsbyteushortuintulongfloatdouble
  • CS1664: буфер фиксированного размера длины "длина" и тип "тип" слишком велик
  • CS1665: буферы фиксированного размера должны иметь длину больше нуля
  • CS1666: нельзя использовать буферы фиксированного размера, содержащиеся в нефиксированных выражениях. Попробуйте использовать фиксированную инструкцию.
  • CS1708: доступ к буферам фиксированного размера можно получить только через локальные или поля
  • CS1716: не используйте атрибут 'System.Runtime.CompilerServices.FixedBuffer' . Вместо этого используйте модификатор поля fixed.
  • CS7092: фиксированный буфер может иметь только одно измерение.
  • CS8372: не используйте атрибут 'System.Runtime.CompilerServices.FixedBuffer' в свойстве
  • CS9049: фиксированное поле не должно быть полем ссылок.

Эти ошибки возникают при работе с буферами фиксированного размера. Буферы фиксированного размера являются массивами, внедренными непосредственно в структуры, и в основном используются для сценариев взаимодействия. Дополнительные сведения см. в разделе " Буферы фиксированного размера".

Чтобы правильно объявлять и использовать буферы фиксированного размера, выполните приведенные ниже действия.

  • Укажите размер массива после имени поля с помощью положительной целочисленной константы (CS1641, CS1665). Общий размер буфера (число элементов, умноженное на размер элемента), не должен превышать 2^31 байт (CS1664).
  • Объявляйте буферы фиксированного размера только в структуры, а не в классах (CS1642). Используйте обычный массив, если требуется поле в классе.
  • Используйте один из поддерживаемых типов элементов: bool, byteshortintlongcharsbyteushortuintulongfloatилиdouble (CS1663).
  • Используйте конструкцию fixed, чтобы закрепить содержащую структуру перед доступом к буферу (CS1666).
  • Доступ к буферам фиксированного размера только через локальные или поля, а не через промежуточные выражения (CS1708).
  • fixed Используйте модификатор полей вместо атрибута System.Runtime.CompilerServices.FixedBuffer (CS1716). Не применяйте этот атрибут к свойствам (CS8372).
  • Объявите фиксированные буферы только с одним измерением (CS7092). Многомерные фиксированные буферы не поддерживаются.
  • Не объявляйте буферы фиксированного размера как ref поля (CS9049). Буферы фиксированного размера должны быть полями значений.

Указатели функций

  • CS8812: не удается преобразовать группу методов "method" в тип указателя без функции "type".

Чтобы получить указатель функции, используйте оператор адреса с явным приведением типа указателя функции. Не используйте оператор получения адреса & для назначения групп методов к void* или другим типам, не являющимся указателями на функции. Дополнительные сведения см. в указателях функций.