Поделиться через


Устраните ошибки и предупреждения в объявлениях операторов и при переполнении

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

  • CS0031: не удается преобразовать константное значение "value" в тип
  • CS0056: несогласованная доступность: возвращаемый тип 'type' менее доступен, чем оператор 'оператор'
  • CS0057: Несогласованная доступность: тип параметра 'type' менее доступен, чем оператор 'operator'
  • CS0215: возвращаемый тип оператора True или False должен быть логическим.
  • CS0216: оператор "оператор" требует, чтобы соответствующий оператор "missing_operator" также был определен
  • CS0217: для применения в качестве оператора короткого канала определяемый пользователем логический оператор ("operator") должен иметь тот же тип возвращаемого значения, что и тип его 2 параметров.
  • CS0218: Тип ('type') должен содержать объявления операторов true и false
  • CS0220: операция переполнена во время компиляции в режиме проверки
  • CS0221: Константное значение 'value' не может быть преобразовано в тип 'type' (используйте синтаксис 'unchecked' для обхода)
  • CS0448: возвращаемый тип для ++ или -- оператор должен быть содержащим типом или производным от содержащего типа
  • CS0463: оценка десятичного константного выражения завершилась ошибкой: "error"
  • CS0543: "перечисление": значение перечислителя слишком велико, чтобы соответствовать его типу
  • CS0552: "подпрограмма преобразования" : определяемое пользователем преобразование в интерфейс или из интерфейса
  • CS0553: "подпрограмма преобразования": определяемое пользователем преобразование в/из базового класса
  • CS0554: "подпрограмма преобразования" : определяемое пользователем преобразование в производный класс или из него
  • CS0555: определяемый пользователем оператор не может принимать объект типа контейнера и преобразовывать его в объект типа контейнера.
  • CS0556: определяемое пользователем преобразование должно преобразовывать в или из включающего типа
  • CS0557: повторяющееся пользовательское преобразование в типе
  • CS0558: определяемый пользователем оператор должен быть объявлен статическим и общедоступным
  • CS0559: тип параметра для ++ или -- оператора должен быть содержащим типом
  • CS0562: параметр унарного оператора должен быть содержащим типом
  • CS0563: один из параметров двоичного оператора должен быть содержащим типом
  • CS0564: первый операнд перегруженного оператора shift должен иметь тот же тип, что и содержащий тип, а тип второго операнда должен быть инте
  • CS0567: интерфейсы не могут содержать операторы
  • CS0590: определяемые пользователем операторы не могут возвращать void
  • CS0594: константа с плавающей запятой находится вне диапазона типа "type"
  • CS0652: сравнение с целочисленной константой является бесполезным; константа выходит за пределы диапазона типа "type"
  • CS0659: "class" переопределяет Object.Equals(object o), но не переопределяет Object.GetHashCode()
  • CS0660: тип определяет operator == или operator !=, но не переопределяет Object.Equals(object o)
  • CS0661: тип определяет operator == и operator !=, но не переопределяет Object.GetHashCode()
  • CS0715: статические классы не могут содержать определяемые пользователем операторы
  • CS1021: слишком большая целочисленная константа
  • CS1037: ожидается перегружаемый оператор
  • CS1553: объявление недопустимо; используйте оператор <modifier dest-type> (...) вместо
  • CS8930: явная реализация определяемого пользователем оператора должна быть объявлена статической
  • CS8931: определяемое пользователем преобразование в интерфейсе должно преобразовываться в параметр типа или из параметра типа в заключающем типе, ограниченном для заключающего типа.
  • CS8778: Константа 'value' может вызвать переполнение 'type' во время выполнения (используйте синтаксис 'unchecked', чтобы переопределить это)
  • CS8973: операция может привести к переполнению во время выполнения (используйте синтаксис 'unchecked', чтобы переопределить)
  • CS9023: не удается проверить оператор.
  • CS9024: Невозможно использовать оператор в необработанном виде.
  • CS9025: оператору требуется также объявить соответствующую не проверенную версию.
  • CS9027: Неожиданное ключевое слово 'unchecked'.
  • CS9308: определяемый пользователем оператор должен быть объявлен общедоступным.
  • CS9310: Возвращаемый тип у этого оператора должен быть void.
  • CS9311: тип не реализует член интерфейса. Тип не может реализовать член, так как один из них не является оператором.
  • CS9312: Тип не может переопределить унаследованный член, поскольку один из них не является оператором.
  • CS9313: перегруженный оператор составного присваивания принимает один параметр.
  • CS9340: оператор не может применяться к операндам. Отображается ближайший неприменимый кандидат.
  • CS9341: оператор не может применяться к операнду. Отображается ближайший неприменимый кандидат.
  • CS9342: разрешение операторов неоднозначно между следующими элементами.

Требования к подписи оператора

  • CS0448: возвращаемый тип для оператора ++ или -- должен быть содержащим типом или производным от содержащего типа.
  • CS0559: тип параметра для ++ или -- оператора должен быть содержащим типом.
  • CS0562: параметр унарного оператора должен быть содержащим типом.
  • CS0563: один из параметров двоичного оператора должен быть содержащим типом.
  • CS0564: Первый операнд перегруженного оператора сдвига должен иметь тот же тип, что и содержащий тип, а тип второго операнда должен быть int.
  • CS0567: интерфейсы не могут содержать операторы.
  • CS0590: операторы, определённые пользователем, не могут возвращать "void".
  • CS9310: Тип возвращаемого значения данного оператора должен быть void.
  • CS9340: оператор не может применяться к операндам. Отображается ближайший неприменимый кандидат.
  • CS9341: оператор не может быть применён к операнду. Отображается наиболее подходящий, но неприменимый кандидат.
  • CS9342: разрешение операторов неоднозначно между следующими элементами.

Каждый тип оператора имеет определенные требования к параметру и возвращаемого типа, определенные спецификацией языка. Полные правила перегрузки операторов см. в разделе " Перегрузка операторов " и "Операторы " в спецификации C#.

  • Измените возвращаемый тип оператора ++ или -- на содержащий тип или тип, производный от него (CS0448). Язык требует, чтобы операторы инкремента и декремента возвращали значение, совместимое с содержащим типом, чтобы результат можно было присвоить той же переменной.
  • Измените параметр операторов ++ или -- на содержащий тип (CS0559). Операторы инкремента и декремента должны работать с экземплярами собственного типа.
  • Измените параметр унарного оператора на содержащий тип (CS0562). Унарные операторы должны принимать операнду типа, объявляющего их.
  • Убедитесь, что хотя бы один параметр двоичного оператора является содержащим типом (CS0563). Двоичные операторы должны включать декларируемый тип, чтобы компилятор смог разрешить их с помощью этого типа.
  • Измените первый параметр оператора shift на содержащий тип и второй параметр int (CS0564). Язык определяет операторы сдвига с определенной сигнатурой: тип, который сдвигается, и целочисленное значение для размера сдвига.
  • Перенесите определения операторов из интерфейсов в классы или структуры (CS0567). Объявления традиционных операторов (нестатических абстрактных) не допускаются в интерфейсах. Сведения о статических абстрактных операторах в интерфейсах см. в разделе "Статические абстрактные" и "Ошибки элементов виртуального интерфейса".
  • Измените возвращаемый тип оператора на непустый тип (CS0590). Большинство определяемых пользователем операторов должны возвращать значение. Исключением являются составные операторы присваивания, для которых требуется void возвращаемый тип (CS9310).
  • Исправьте типы параметров или добавьте отсутствующие перегрузки оператора, чтобы компилятор смог найти соответствующий оператор для типов операнда, используемых на сайте вызова (CS9340, CS9341). Если применимый оператор не существует, компилятор показывает ближайшего кандидата для диагностики несоответствия.
  • Добавьте явные приведения на сайте вызова или укажите более конкретные перегрузки, чтобы устранить неоднозначность, если перегрузки нескольких операторов совпадают одинаково хорошо (CS9342).

Это важно

Требования к сигнатурам для бинарных статических операторов и соответствующие операторы составного присваивания экземпляра различаются. Убедитесь, что подпись соответствует нужному объявлению.

Требования к объявлению оператора

  • CS0558: определяемый пользователем оператор должен быть объявлен статическим и общедоступным.
  • CS0715: статические классы не могут содержать определяемые пользователем операторы.
  • CS1037: ожидается перегружаемый оператор.
  • CS1553: объявление недопустимо; используйте оператор modifier <dest-type> (...) вместо.
  • CS9308: определяемый пользователем оператор должен быть объявлен общедоступным.

Язык требует определенных модификаторов и синтаксиса для объявлений операторов. Полные правила см. в разделе " Перегрузка операторов " и "Определяемые пользователем операторы преобразования".

  • Добавьте оба модификатора static и public к объявлению оператора (CS0558, CS9308). Язык C# требует, чтобы все определяемые пользователем операторы были статическими и общедоступными, чтобы они были доступными и вызываемыми без экземпляра.
  • Перемещение объявления оператора из статического класса в нестатический класс или структуру (CS0715). Статические классы не могут иметь экземпляры, поэтому определяемые пользователем операторы , которые работают с экземплярами их содержащего типа, не имеют значения в статических классах.
  • Замените недопустимый символ оператора допустимым перегрузочным оператором (CS1037). Можно перегружать только определенные операторы, определенные языком.
  • Исправьте синтаксис, чтобы соответствовать требуемой форме оператора преобразования: public static implicit operator <dest-type>(<source-type> parameter) или public static explicit operator <dest-type>(<source-type> parameter) (CS1553). Компилятор ожидает, что операторы преобразования будут соответствовать определённому шаблону декларации.

Ошибки, связанные с явными реализациями интерфейсов операторов в статических абстрактных интерфейсах, см. в разделе "Статические абстрактные" и "Ошибки элементов виртуального интерфейса".

Несогласованная доступность

  • CS0056: Несогласованная доступность: возвращаемый тип 'type' менее доступен, чем оператор 'operator'.
  • CS0057: Несогласованная доступность: тип параметра 'type' менее доступен, чем оператор 'operator'.

Все типы, используемые в сигнатуре публичного оператора, должны быть по крайней мере настолько же доступны, насколько и сам оператор. Полные правила см. в разделе " Модификаторы доступа " и ограничения специальных возможностей в спецификации C#.

  • Измените возвращаемый тип на тип, который по крайней мере так же доступен, как оператор, или уменьшите доступность оператора, чтобы соответствовать типу возвращаемого значения (CS0056). Оператор public не может разглашать тип с более ограниченным доступом через возвращаемое значение, так как вызывающие объекты за пределами сборки не смогут использовать результат.
  • Измените тип параметра на тип, который по крайней мере так же доступен, как оператор, или уменьшите доступность оператора, чтобы соответствовать типу параметра (CS0057). Оператор public не может требовать менее доступный тип в качестве параметра, так как вызывающие пользователи за пределами сборки не смогут предоставить аргумент.

Определяемые пользователем ограничения преобразования

  • CS0552: определяемое пользователем преобразование в интерфейс и из нее.
  • CS0553: определяемое пользователем преобразование в базовый класс или из нее.
  • CS0554: определяемое пользователем преобразование в производный класс или из него.
  • CS0555: определяемый пользователем оператор не может принимать объект обертывающего типа и преобразовывать в объект обертывающего типа.
  • CS0556: определяемое пользователем преобразование должно преобразовываться в вложенный тип или из него.
  • CS0557: повторяющееся пользовательское преобразование в типе.

Язык C# ограничивает, какие типы могут участвовать в пользовательских преобразованиях. Полные правила см. в разделе "Определяемые пользователем операторы преобразования " и операторы преобразования в спецификации C#.

  • Удалите оператор преобразования, который преобразуется в тип интерфейса или из него (CS0552). Язык программирования запрещает определяемые пользователем преобразования, связанные с типами интерфейсов, так как преобразования интерфейсов обрабатываются с помощью ссылочных преобразований и упаковки в системе типов. Вместо этого используйте явные реализации интерфейса или вспомогательные методы.
  • Удалите оператор преобразования, который преобразуется в базовый класс или из него (CS0553). Преобразования между типом и его базовым классом уже существуют через неявные преобразования ссылок (восходящее преобразование) и явные преобразования ссылок (нисходящее преобразование), поэтому определяемое пользователем преобразование создаст неоднозначность.
  • Удалите оператор преобразования, который преобразует в или из производного класса (CS0554). Как и преобразования базового класса, преобразования между типом и его производными типами встроены в язык через наследование, и определяемые пользователем преобразования будут конфликтовить с ними.
  • Удалите оператор преобразования, который преобразует вложенный тип в себя (CS0555). Каждый тип уже имеет неявное преобразование идентичности в себя, поэтому определяемое пользователем преобразование из типа в тот же тип является излишним и не допускается.
  • Измените один из типов в операторе преобразования таким образом, чтобы исходный или целевой тип был вложенным типом (CS0556). Определяемое пользователем преобразование должно включать тип, объявляющий его, — невозможно определить преобразование между двумя несвязанными внешними типами в третьем типе.
  • Удалите оператор преобразования дубликата или измените один из повторяющихся операторов, чтобы исходные и целевые типы отличались от других (CS0557). Тип может объявлять только одно неявное и одно явное преобразование для любой заданной пары исходных и целевых типов.

Логические операторы и операторы короткого замыкания

  • CS0215: возвращаемый тип оператора true или false должен быть bool.
  • CS0216: оператор требует также определения соответствующего оператора.
  • CS0217: для применения в качестве оператора короткого канала определяемый пользователем логический оператор должен иметь тот же тип возвращаемого значения, что и тип его 2 параметров.
  • CS0218: тип должен содержать объявления операторов true и false.

Для языка C# требуются определенные пары и сигнатуры для логических операторов и оценки короткого канала. Полные правила см. в разделах операторы истинности и ложности, булевые логические операторы, и определяемые пользователем условные логические операторы в спецификации C#.

  • Измените тип возвращаемого значения у operator true и operator false на bool (CS0215). Эти операторы определяют, является ли значение логически истинным или ложным, поэтому язык требует, чтобы они возвращали bool.
  • Определите соответствующий парный оператор (CS0216). Язык требует, чтобы определенные операторы объявлялись в парах: operator == с operator !=, operator < с operator >, operator <= с operator >= и operator true с operator false.
  • Измените тип возвращаемого значения & или | определяемого пользователем оператора, чтобы соответствовать типам обоих параметров (CS0217). Для оценки короткого замыкания (&& и ||) компилятору требуется, чтобы возвращаемый тип операторов & или |, оба типа параметров и содержащий тип были одинакового типа.
  • Добавьте оба operator true и operator false объявления в тип (CS0218). Компилятор переписывает && и || с использованием operator true, operator false, а также соответствующего оператора & или |, поэтому все три должны присутствовать для работы короткозамкнутой оценки.

Проверенные операторы

  • CS9023: Оператор не может быть приведен в состояние проверяемости
  • CS9024: оператор не может быть снят с флажка
  • CS9025: для проверенного оператора требуется также объявить соответствующую непроверенную версию.
  • CS9027: непредвиденное ключевое слово 'unchecked'

Ключевые слова checked и unchecked можно применять только к определенным объявлениям операторов. Полные правила см. в статье арифметические операторы и определяемые пользователем операторы.

  • Удалите ключевое checkedunchecked слово из неподдерживаемого оператора (CS9023, CS9024). Только арифметические операторы +, -, *, /, ++, -- и явные операторы преобразования поддерживают проверенные и непроверенные варианты. Другие операторы, такие как операторы сравнения или равенства, не имеют четкого поведения переполнения и не могут быть отмечены как проверенные или непроверенные.
  • Добавьте соответствующую не проверенную версию оператора (CS9025). Оператор checked предоставляет поведение, вызывающее переполнение, но компилятору также требуется соответствующая неконтролируемая версия для использования в unchecked контекстах и в качестве значения по умолчанию, если ни тот контекст не указан.
  • Удалите ключевое слово из недопустимой unchecked позиции (CS9027). Ключевое unchecked слово в объявлении оператора допустимо только в рамках синтаксиса оператора (например, public static explicit operator unchecked int(MyType t)). Размещение его в другом месте объявления приводит к ошибке синтаксиса.

Требования к интерфейсу и наследованию

  • CS9311: тип не реализует член интерфейса. Тип не может реализовать член, так как один из них не является оператором
  • CS9312: тип не может переопределить наследуемый член, так как один из них не является оператором
  • CS9313: Этот перегруженный оператор составного назначения принимает один параметр

Компилятор применяет строгое сопоставление между объявлениями операторов и элементами интерфейса или элементами базового класса, которые они реализуют или переопределяют. Полные правила см. в разделе "Перегрузка операторов " и "Интерфейсы".

  • Измените элемент реализации на объявление оператора, соответствующее члену оператора интерфейса, или измените член интерфейса на метод, если реализующий элемент является методом (CS9311). Оператор может реализовать только член интерфейса, который также объявлен в качестве оператора — вы не можете выполнить контракт оператора, используя обычный метод, и наоборот.
  • Измените переопределяющий член на объявление оператора, соответствующее члену оператора базового класса, или измените член базового класса на метод, если производный член класса является методом (CS9312). Как и реализация интерфейса, переопределение должно соответствовать типу члена, который переопределяется — оператор не может переопределить неоператорный член.
  • Измените объявление оператора составного назначения, чтобы принять ровно один параметр (CS9313). Операторы составного присваивания являются членами экземпляра, где левый операнд неявно является this, поэтому только правый операнд объявляется как параметр.

Операторы равенства

  • CS0659: "class" переопределяет Object.Equals(object o), но не переопределяет Object.GetHashCode()
  • CS0660: тип определяет оператор == или оператор != , но не переопределяет Object.Equals(object o)
  • CS0661: тип определяет оператор == или оператор != но не переопределяет Object.GetHashCode()

Компилятор требует, чтобы переопределения, связанные с равенством, и определения операторов оставались синхронизированными. При переопределении Object.Equals или определении operator == / operator !=необходимо также указать связанные переопределения. Полные правила см. в разделах Определение равенства значений для типа и Операторы равенства.

  • Добавьте переопределение для Object.GetHashCode, когда вы переопределяете Object.Equals (CS0659). Хэш-коллекции, такие как Dictionary<TKey,TValue> и HashSet<T>, полагаются на контракт, что если два объекта равны, они должны возвращать один и тот же хэш-код. Без соответствующего переопределения GetHashCode объекты, которые сравниваются как равные, могут хэшироваться в разные корзины, что приводит к бесшумному сбою при поиске и дедупликации.
  • Добавьте переопределение Object.Equals при определении operator == или operator != (CS0660). Код, напрямую вызывающий Equals, включая многие API платформы, методы LINQ и операции с коллекциями, не будет использовать ваш настраиваемый оператор. Без согласованного Equals переопределения одни и те же два объекта могут считаться равными для ==, но не для Equals, что приводит к непредсказуемому поведению.
  • Добавьте переопределение Object.GetHashCode, когда вы определяете operator == или operator != (CS0661). В случае, как и CS0659, вам необходимо GetHashCode следовать семантике равенства. Если operator == считает два объекта равными, но они возвращают разные хэш-коды, коллекции, основанные на хэшах, не будут функционировать корректно.

Ошибки переполнения и недостаточного заполнения

  • CS0031: не удается преобразовать константное значение "value" в тип
  • CS0220: операция переполнена во время компиляции в режиме проверки
  • CS0221: Константное значение 'value' не удается преобразовать в 'type' (используйте синтаксис 'unchecked' для переопределения)
  • CS0463: оценка десятичного константного выражения завершилась ошибкой: "error"
  • CS0543: "перечисление": значение перечислителя слишком велико, чтобы соответствовать его типу
  • CS0594: константа с плавающей запятой находится вне диапазона типа "type"
  • CS0652: сравнение с целочисленной константой является бесполезным; константа выходит за пределы диапазона типа "type"
  • CS1021: слишком большая целочисленная константа
  • CS8778: константное значение "value" может переполнить 'тип' в время выполнения (используйте синтаксис 'unchecked', чтобы переопределить)
  • CS8973: операция может привести к переполнению во время выполнения (используйте синтаксис 'unchecked', чтобы переопределить)

Компилятор вычисляет константные выражения во время компиляции и сообщает об ошибках или предупреждениях, когда значение превышает допустимый диапазон целевого типа. Полные правила см. в проверенных и непроверенных операторах и целочисленных типах.

  • Измените константное значение на одно, которое соответствует диапазону целевого типа или измените целевой объект на более крупный числовый тип (CS0031). Компилятор не может неявно сузить константу, которая не вписывается в диапазон. Например, присвоение 256 переменной типа byte (диапазон 0–255) вызывает эту ошибку. Если усечение намеренно, используйте явное приведение в контексте unchecked.
  • Исправьте арифметику в константном выражении таким образом, чтобы результат соответствовал целевому типу, или поместите выражение в неконтролируемый контекст, чтобы разрешить незаметное переполнение (CS0220). Компилятор оценивает все константное выражение во время компиляции в проверяемом контексте по умолчанию, поэтому промежуточные или окончательные результаты, превышающие диапазон типа, вызывают эту ошибку.
  • Измените значение константы или целевой тип, чтобы преобразование было допустимым, или заключите выражение в unchecked контексте, если вы намеренно хотите усеченный результат (CS0221). В отличие от CS0220, эта ошибка применяется к явным преобразованиям констант, в которых исходное значение не соответствует типу назначения.
  • Упростите или разделите константное decimal выражение, чтобы оно оставалось в пределах диапазона и точности типа decimal (CS0463). Тип decimal имеет максимальное значение примерно $7,9 \times 10^{28}$ и 28–29 значимых цифр, а компилятор оценивает полное выражение во время компиляции.
  • Измените значение элемента перечисления на тот, который соответствует базовому типу перечисления, или измените базовый тип на более крупный целочисленный тип (CS0543). По умолчанию перечисления используют int в качестве базового типа. Если значение члена превышает диапазон базового типа, укажите более крупный тип, например long.
  • Измените константу с плавающей запятой на значение в диапазоне целевого типа или используйте тип более высокой точности, например double или float (CS0594). Тип float поддерживает значения до примерно $3,4 \times 10^{38}$, и double поддерживает до примерно $1,7 \times 10^{308}$.
  • Удалите или исправьте сравнение, чтобы константы были в диапазоне типа переменной (CS0652). Сравнение переменной byte с 300, например, никогда не может быть истинным, поэтому компилятор предупреждает, что сравнение не имеет смысла. Это предупреждение часто указывает на ошибку логики или несоответствие между типом переменной и предполагаемым диапазоном значений.
  • Используйте более крупный числовый тип или разделите значение по нескольким операциям (CS1021). Эта ошибка возникает, когда целочисленный литерал превышает диапазон даже самого крупного целого типа (ulong, до $1,8 \times 10^{19}$). Для значений, превышающих этот диапазон, рекомендуется использовать BigInteger.
  • Заключите выражение в контекст unchecked, чтобы подавить предупреждение, или измените значение, чтобы оно соответствовало диапазону целевого типа (CS8778). Это предупреждение указывает на постоянное преобразование, которое может потерять данные во время выполнения. Компилятор не может доказать, что переполнение определенно произойдет, но идентифицирует риск.
  • Упакуйте выражение в контекст unchecked, чтобы подавить предупреждение, или перестройте арифметику, чтобы избежать потенциального переполнения (CS8973). Это предупреждение похоже на CS8778, но применяется к арифметическим операциям, а не преобразованиям; компилятор обнаруживает, что операция может переполниться во время выполнения.