解决用户定义的运算符声明中的错误和警告

本文介绍以下编译器错误:

  • CS0056可访问性不一致:返回类型"type"的可访问性低于运算符"operator"
  • CS0057不一致的可访问性:参数类型“type”的可访问性低于运算符“operator”
  • CS0215运算符 True 或 False 的返回类型必须为布尔值
  • CS0216运算符“operator”需要同时定义匹配的运算符“missing_operator”
  • CS0217为了作为短路运算符适用,用户定义的逻辑运算符('operator')必须具有与其 2 个参数的类型相同的返回类型。
  • CS0218类型('type')必须包含运算符 true 和运算符 false 的声明
  • CS0448运算符++--的返回类型必须为包含类型或派生自包含类型
  • CS0552“转换例程”:用户定义的到/从接口转换
  • CS0553“转换例程”:用户定义的到基类/从基类转换
  • CS0554“转换例程”:用户定义的到派生类/从派生类转换
  • CS0555用户定义的运算符不能接受封闭类型的对象并转换为封闭类型的对象
  • CS0556用户定义的转换必须转换为封闭类型或从封闭类型转换
  • CS0557类型中重复用户定义转换
  • CS0558用户定义的运算符必须声明为静态和公共运算符
  • CS0559++--运算符的参数类型必须是包含类型
  • CS0562一元运算符的参数必须是包含类型
  • CS0563二进制运算符的参数之一必须是包含类型
  • CS0564重载移位运算符的第一个作数必须与包含类型具有相同的类型,并且第二个作数的类型必须为 int
  • 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操作员需要声明匹配的非检查版本。
  • 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 作为第二个参数用于移位运算符(CS0564)。
  • 不要在接口(CS0567)中声明运算符。 接口不能包含运算符实现。
  • 从大多数运算符(CS0590)返回非 void 类型,但需要 void 返回的特定运算符除外(CS9310)。
  • 提供接受正确参数类型的运算符重载以避免解决失败(CS9340CS9341)。
  • 使用显式强制转换或提供更具体的重载(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> (...”。
  • CS8930:用户定义的 运算符的显式实现必须是静态的。
  • CS8931显式实现必须声明为公共实现,才能在类型中实现接口成员。
  • CS9308用户定义的运算符必须声明为公共运算符。

若要正确声明运算符,请遵循修饰符和包含类型的这些要求。 有关详细信息,请参阅 运算符重载用户定义的转换运算符

  • 同时声明运算符 staticpublic 修饰符(CS0558CS9308)。
  • 不要在静态类(CS0715)中声明运算符。 使用常规类或结构。
  • 使用有效的可重载运算符符号(CS1037)。
  • 遵循正确的转换运算符语法: public static implicit/explicit operator <dest-type>(<source-type> parameter)CS1553)。
  • 确保运算符的显式接口实现为 staticCS8930) 和 publicCS8931)。

以下示例演示声明错误:

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 的返回类型必须为布尔值。
  • CS0216该运算符需要同时定义匹配的运算符。
  • CS0217为了作为短路运算符适用,用户定义的逻辑运算符必须与其 2 个参数的类型具有相同的返回类型。
  • CS0218类型必须包含运算符 true 和运算符 false 的声明。

若要正确定义逻辑运算符,请遵循这些配对和签名要求。 有关详细信息,请参阅 true 和 false 运算符布尔逻辑运算符用户定义的条件逻辑运算符

  • 返回booloperator trueoperator false(CS0215)。
  • 定义所需的配对运算符(CS0216):
    • operator == 需要 operator !=
    • operator < 需要 operator >
    • operator <= 需要 operator >=
    • operator true 需要 operator false
  • 将返回类型与使用自定义类型的短路运算符(&|)的参数类型匹配(CS0217)。
  • 使用自定义类型时,在布尔上下文中实现operator trueoperator 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已检查的操作员需要声明匹配的非检查版本

若要正确使用已检查的运算符,请遵循这些要求。 有关详细信息,请参阅 算术运算符用户定义的检查运算符

  • 仅对支持的算术运算符应用checkedunchecked关键字:+-*/++、、--和显式转换(CS9023、CS9024)。
  • 声明已检查的运算符(CS9025)时,同时提供已检查的版本和未检查的版本。 编译器需要两者来处理不同的上下文。

接口和继承要求

  • CS9311类型不实现接口成员。类型无法实现成员,因为其中一个不是运算符
  • CS9312类型无法替代继承的成员,因为其中一个不是操作员
  • CS9313重载复合赋值运算符接受一个参数

若要正确实现和替代运算符,请遵循这些要求。 有关详细信息,请参阅 运算符重载接口

  • 确保运算符声明与接口成员的签名和类型匹配(CS9311)。 运算符无法实现非运算符成员。
  • 验证被重写的继承成员是否也是运算符(CS9312)。 运算符不能重载非运算符成员。
  • 使用一个参数声明复合赋值运算符(CS9313)。 左操作数是this的隐式参数。

相等运算符

  • CS0660类型定义运算符 == 或运算符 != 但不会重写 Object.Equals(object o)
  • CS0661类型定义运算符 == 或运算符 != 但不会重写 Object.GetHashCode()

若要正确实现相等性,在定义自定义相等运算符时重写相应的 Object 方法。 有关详细信息,请参阅如何为类型定义值相等相等运算符

重写这些方法可确保不同 API 和集合类型之间的一致相等行为。