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


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

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

  • CS0056: несогласованная доступность: возвращаемый тип 'type' менее доступен, чем оператор 'оператор'
  • CS0057: Несогласованная доступность: тип параметра 'type' менее доступен, чем оператор 'operator'
  • CS0215: возвращаемый тип оператора True или False должен быть логическим.
  • CS0216: оператор "оператор" требует, чтобы соответствующий оператор "missing_operator" также был определен
  • CS0217: для применения в качестве оператора короткого канала определяемый пользователем логический оператор ("operator") должен иметь тот же тип возвращаемого значения, что и тип его 2 параметров.
  • CS0218: Тип ('type') должен содержать объявления операторов true и false
  • CS0448: возвращаемый тип для ++ или -- оператор должен быть содержащим типом или производным от содержащего типа
  • CS0552: "подпрограмма преобразования" : определяемое пользователем преобразование в интерфейс или из интерфейса
  • CS0553: "подпрограмма преобразования": определяемое пользователем преобразование в/из базового класса
  • CS0554: "подпрограмма преобразования" : определяемое пользователем преобразование в производный класс или из него
  • CS0555: определяемый пользователем оператор не может принимать объект типа контейнера и преобразовывать его в объект типа контейнера.
  • CS0556: определяемое пользователем преобразование должно преобразовывать в или из включающего типа
  • CS0557: повторяющееся пользовательское преобразование в типе
  • CS0558: определяемый пользователем оператор должен быть объявлен статическим и общедоступным
  • CS0559: тип параметра для ++ или -- оператора должен быть содержащим типом
  • CS0562: параметр унарного оператора должен быть содержащим типом
  • CS0563: один из параметров двоичного оператора должен быть содержащим типом
  • CS0564: первый операнд перегруженного оператора shift должен иметь тот же тип, что и содержащий тип, а тип второго операнда должен быть инте
  • CS0567: интерфейсы не могут содержать операторы
  • CS0590: определяемые пользователем операторы не могут возвращать void
  • CS0660: тип определяет operator == или operator !=, но не переопределяет Object.Equals(object o)
  • CS0661: тип определяет operator == и operator !=, но не переопределяет Object.GetHashCode()
  • CS0715: статические классы не могут содержать определяемые пользователем операторы
  • CS1037: ожидается перегружаемый оператор
  • CS1553: объявление недопустимо; используйте оператор <modifier dest-type> (...) вместо
  • CS8930: явная реализация определяемого пользователем оператора должна быть объявлена статической
  • CS8931: определяемое пользователем преобразование в интерфейсе должно преобразовываться в параметр типа или из параметра типа в заключающем типе, ограниченном для заключающего типа.
  • 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: разрешение операторов неоднозначно между следующими элементами.

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

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

Это важно

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

В следующем примере показаны ошибки подписи:

class C1
{
    public static int operator ++(C1 c) => 0;   // CS0448
    public static C1 operator --(C1 c) => null;   // OK
}
public class C2
{
    public static implicit operator int(C2 x) => 0;
    public static implicit operator C2(int x) => new C2();
    public static int operator ++(int aa) => 0;  // CS0559
}
public class C3
{
    public static implicit operator int(C3 x) => 0;
    public static implicit operator C3(int x) => null;
    public static C3 operator +(int aa) => 0;   // CS0562
}
public class C4
{
    public static implicit operator int(C4 x) => 0;
    public static implicit operator C4(int x) => null;
    public static int operator +(int aa, int bb) => 0;   // CS0563
}
class C5
{
    // To correct, change second operand to int, like so:
    // public static int operator << (C c1, int c2)
    public static int operator <<(C5 c1, C5 c2) => 0; // CS0564
}
interface IA
{
    int operator +(int aa, int bb);   // CS0567
}
public class C6
{
    public static void operator +(C6 A1, C6 A2) { }  // CS0590
}

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

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

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

  • Объявите операторы с модификаторами static и public (CS0558, CS9308).
  • Не объявляйте операторы в статических классах (CS0715). Используйте обычные классы или структуры.
  • Используйте допустимые, перегружаемые символы операторов (CS1037).
  • Следуйте правильному синтаксису для операторов преобразования(public static implicit/explicit operator <dest-type>(<source-type> parameter)CS1553).

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

В следующем примере показаны ошибки объявления:

public class C
{
    static implicit operator int(C aa) => 0;   // CS0558, add public
}
public static class C1
{
    public static int operator +(C1 c) => 0;  // CS0715
}
class C2
{
    public static int implicit operator (C2 f) => 6;   // CS1553
}

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

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

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

  • Убедитесь, что возвращаемые типы имеют по крайней мере такую же доступность, как и оператор (CS0056).
  • Убедитесь, что типы параметров имеют по крайней мере такую же доступность, как оператор (CS0057).

При объявлении public оператора все типы, используемые в качестве параметров или возвращаемых значений, также должны быть общедоступными.

В следующем примере показаны ошибки доступности.

class C { }

public class C2
{
    public static implicit operator C(C2 a) => new C();   // CS0056
}

public class C3
{
    public static implicit operator C3(C c) => new C3();   // CS0057
}

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

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

Чтобы создать допустимые пользовательские операторы преобразования, следуйте этим ограничениям. Дополнительные сведения см. в разделе Операторы пользовательского преобразования.

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

В следующем примере показаны ошибки ограничения преобразования:

public interface I
{
}
public class C
{
    public static implicit operator I(C aa) => default;// CS0552
}

public class B
{
}
public class D : B
{
    public static implicit operator B(D aa) => new B();// CS0553
}

public class B2
{
    // delete the conversion routine to resolve CS0554
    public static implicit operator B2(D2 d) => new B2();// CS0554
}
public class D2 : B2 { }

public class C2
{
    public static implicit operator C2(C2 aa) => new C2();   // CS0555
}

public class C3
{
    public static implicit operator int(byte aa) => 0;   // CS0556
}

public class C4
{
    public static implicit operator int(C4 aa) => 0;

    // CS0557, delete duplicate
    public static explicit operator int(C4 aa) => 0;
}

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

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

Чтобы правильно определить логические операторы, следуйте этим требованиям связывания и подписи. Дополнительные сведения см. в разделе true и false;логические операторы типа Boolean и определяемые пользователем условные логические операторы.

  • Возврат bool из operator true и operator false (CS0215).
  • Определение обязательных парных операторов (CS0216):
    • operator == Требует operator !=
    • operator < Требует operator >
    • operator <= Требует operator >=
    • operator true Требует operator false
  • Сопоставьте тип возвращаемого значения с типами параметров для короткозамкнутых операторов (& и |), которые работают с пользовательскими типами (CS0217).
  • Реализуйте оба operator true и operator false при использовании пользовательских типов в логических контекстах, таких как && и || (CS0218).

В следующем примере показаны ошибки логических операторов:

class C
{
    public static int operator true(C c) => 0;   // CS0215
    public static int operator false(C c) => 0; // CS0215
}

class C2
{
    public static bool operator ==(C2 left, C2 right) => left.Equals(right);   // CS0216

    public override bool Equals(object? o) => base.Equals(o);
    public override int GetHashCode() => base.GetHashCode();
}

public class C3
{
    public static bool operator true(C3 f) => false;
    public static bool operator false(C3 f) => true;
    public static implicit operator int(C3 x) => 0;
    public static int operator &(C3 f1, C3 f2) => new C3();  // CS0217
}

public class C4
{
    public static implicit operator int(C4 x) => 0;
    public static C4 operator &(C4 f1, C4 f2) => new C4();

    public static void Main()
    {
        C4 f = new C4();
        int i = f && f;   // CS0218, requires operators true and false
    }
}

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

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

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

  • Применять checked или unchecked ключевые слова только к поддерживаемым арифметическим операторам: +, -, *, /++, --и явным преобразованиям (CS9023, CS9024).
  • Предоставьте проверенные и снятые версии при объявлении проверенного оператора (CS9025). Компилятор должен обрабатывать разные контексты.
  • Используйте ключевое unchecked слово только в допустимых контекстах объявления оператора (CS9027). Не размещайте его в местах, где он синтаксически неожиданно.

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

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

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

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

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

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

Чтобы правильно реализовать равенство, переопределите соответствующие Object методы при определении пользовательских операторов равенства. Дополнительные сведения см. в разделах "Как определить равенство значений для типа" и "Операторы равенства".

  • При определении Object.Equals или operator == следует переопределить operator != (CS0660).
  • Переопределите Object.GetHashCode, когда определяете operator == или operator != (CS0661).

Переопределение этих методов обеспечивает согласованное поведение равенства между различными API и типами коллекций.