通过


解决运算符声明和溢出的错误和警告

本文介绍了以下编译器错误和警告:

  • CS0031常量值“value”无法转换为“type”
  • CS0056可访问性不一致:返回类型"type"的可访问性低于运算符"operator"
  • CS0057不一致的可访问性:参数类型“type”的可访问性低于运算符“operator”
  • CS0215运算符 True 或 False 的返回类型必须为布尔值
  • CS0216运算符“operator”需要同时定义匹配的运算符“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重载移位运算符的第一个作数必须与包含类型具有相同的类型,并且第二个作数的类型必须为 int
  • 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操作可能在运行时溢出(使用“未选中”语法替代)
  • CS9023操作符无法设为检查状态。
  • CS9024运算符无法标记为不受检查。
  • CS9025操作员需要声明匹配的非检查版本。
  • CS9027意外关键字“未选中”。
  • 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 运算符的第一个参数更改为包含类型,并将第二个参数更改为 intCS0564)。 该语言使用特定签名定义 Shift 运算符:要移动的类型和整数移位量。
  • 将运算符声明移出接口,并移入类或结构(CS0567)。 接口中不允许使用传统(非静态抽象)运算符声明。 有关接口中的静态抽象运算符,请参阅 静态抽象和虚拟接口成员错误
  • 将运算符的返回类型更改为非 void 类型(CS0590)。 大多数用户定义的运算符必须返回一个值。 例外情况是复合赋值运算符,需要 void 返回类型(CS9310)。
  • 更正参数类型或添加缺少的运算符重载,以便编译器可以找到调用站点中使用的操作数类型的匹配运算符(CS9340,CS9341)。 如果不存在适用的运算符,编译器会显示最接近的候选项,以帮助诊断不匹配。
  • 在调用处添加显式强制转换,或提供更具体的重载,以消除当多个运算符重载同样匹配时的歧义(CS9342)。

重要

静态二进制运算符和相应的实例复合赋值运算符的签名要求不同。 确保签名与所需的声明匹配。

运算符声明要求

  • CS0558用户定义的运算符必须声明为静态和公共运算符。
  • CS0715静态类不能包含用户定义的运算符。
  • CS1037: 需要可重载的运算符。
  • CS1553声明无效,应使用“modifier 运算符 <dest-type> (...”。
  • CS9308用户定义的运算符必须声明为公共运算符。

该语言需要运算符声明的特定修饰符和语法。 有关完整规则,请参阅 运算符重载用户定义的转换运算符

  • staticpublic修饰符都添加到运算符声明(CS0558CS9308)。 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# 规范中的 Access 修饰符辅助功能约束

  • 将返回类型更改为至少与运算符一样可访问的类型,或降低运算符的可访问性以匹配返回类型(CS0056)。 public运算符无法通过其返回值公开不太易访问的类型,因为程序集外部的调用方将无法使用结果。
  • 将参数类型更改为至少作为运算符可访问的类型,或减少运算符的可访问性以匹配参数类型(CS0057)。 public运算符无法将不太易访问的类型作为参数,因为程序集外部的调用方无法提供参数。

用户定义的转换限制

  • CS0552用户定义到/从接口转换。
  • CS0553用户定义的到/从基类的转换。
  • CS0554从派生类到/从派生类进行用户定义的转换。
  • CS0555用户定义的运算符不能采用封闭类型的对象并转换为封闭类型的对象。
  • CS0556用户定义的转换必须转换为封闭类型或从封闭类型转换。
  • CS0557类型中重复用户定义转换。

C# 语言限制哪些类型可以参与用户定义的转换。 有关完整规则,请参阅 C# 规范中的 用户定义的转换运算符转换运算符

  • 删除转换为接口类型或从接口类型转换的转换运算符(CS0552)。 该语言禁止涉及接口类型的用户定义的转换,因为接口转换是通过类型系统的引用转换和装箱进行处理的。 请改用显式接口实现或帮助程序方法。
  • 删除转换为基类或从基类转换的转换运算符(CS0553)。 类型与其基类之间的转换已经通过隐式引用转换(向上转换)和显式引用转换(向下转换)存在,因此用户定义的转换将产生歧义。
  • 移除将对象转换为派生类或从派生类转换的运算符(CS0554)。 与基类转换一样,类型与其派生类型之间的转换通过继承内置于语言中,用户定义的转换将与其冲突。
  • 删除将封闭类型转换为自身(CS0555)的转换运算符。 每种类型都已经具有隐式标识转换本身,因此,从类型到同一类型的用户定义的转换是冗余的,不允许。
  • 更改转换运算符中的其中一种类型,以便源类型或目标类型为封闭类型(CS0556)。 用户定义的转换必须涉及声明它的类型 - 不能在第三种类型的两个不相关的外部类型之间定义转换。
  • 删除重复转换运算符,或更改其中一个重复运算符,以便源类型和目标类型与其他运算符(CS0557)不同。 对于任何给定的源和目标类型对,类型只能声明一个隐式转换和一个显式转换。

布尔运算符和短路运算符

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

C# 语言需要布尔运算符和短路评估的特定配对和签名。 有关完整规则,请参阅 C# 规范中的 true 和 false 运算符布尔逻辑运算符用户定义的条件逻辑运算符

  • 将返回类型operator trueoperator false更改为 boolCS0215)。 这些运算符确定值在逻辑上是 true 还是 false,因此语言要求它们返回 bool
  • 定义匹配的配对运算符(CS0216)。 语言要求将某些运算符声明为对: operator ==operator !=operator < with operator >operator <= with operator >=operator true with operator false
  • 更改用户定义的 &| 运算符的返回类型以匹配这两个参数类型(CS0217)。 对于短路计算(&&||),编译器需要 &| 运算符的返回类型,参数类型和包含类型都为同一类型。
  • 向类型添加operator trueoperator false两个声明(CS0218)。 编译器使用operator trueoperator false以及相应的&|运算符重写&&||,因此这三个元素必须同时存在,以便短路求值功能正常工作。

选中的运算符

  • CS9023无法检查操作员
  • CS9024运算符无法设为未检查状态
  • CS9025已检查的操作员需要声明匹配的非检查版本
  • CS9027意外关键字“未选中”

checkedunchecked关键字只能应用于特定的运算符声明。 有关完整规则,请参阅 算术运算符用户定义的已检查运算符

  • 从不支持的运算符中删除checked 或者 unchecked 关键字(CS9023CS9024)。 只有算术运算符+、、-*/++--和显式转换运算符支持已选中和未选中的变体。 其他运算符(如比较运算符或相等运算符)没有明显的溢出行为,并且无法标记为已选中或未选中。
  • 添加匹配的非检查版本的运算符(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.Equals时添加Object.GetHashCode的重写(CS0659)。 基于哈希的集合,例如 Dictionary<TKey,TValue>HashSet<T>,依赖于一个约定,即两个相等的对象必须返回相同的哈希码。 如果没有匹配的 GetHashCode 覆盖,比较相等的对象可能会哈希到不同的桶,从而导致查找和去重操作以无提示方式失败。
  • 提供Object.Equals的重写,当您定义operator ==operator !=CS0660)时。 直接调用 Equals 的代码(包括许多框架 API、LINQ 方法和集合操作)不会使用自定义运算符。 如果没有一致的 Equals 覆盖,同一两个对象可能被 == 视为相等,但被 Equals 视为不等,从而导致不可预知的行为。
  • 定义operator ==operator !=时添加Object.GetHashCode的重载(CS0661)。 与 CS0659 一样,需要 GetHashCode 与相等语义保持一致。 如果 operator == 认为两个对象相等,但它们返回不同的哈希代码,则基于哈希的集合将无法正常工作。

溢出和下溢错误

  • CS0031常量值“value”无法转换为“type”
  • CS0220在已检查模式下,操作在编译时溢出
  • CS0221常量值“value”无法转换为“type”(使用“unchecked”语法替代)
  • CS0463对十进制常量表达式的计算失败,并出现错误:“error”
  • CS0543“枚举”:枚举器值太大,无法适应其类型
  • CS0594浮点常量不在类型“type”的范围内
  • CS0652与整型常量进行比较是无用的;该常量不在类型“type”的范围内
  • CS1021整型常量太大
  • CS8778常量值“value”可能会在运行时溢出“type”(使用“unchecked”语法替代)
  • CS8973操作可能在运行时溢出(使用“未选中”语法替代)

当某个值超出其目标类型的有效范围时,编译器在编译时计算常量表达式,并报告错误或警告。 有关完整规则,请参阅 已选中和未选中的语句整型类型

  • 将常量值更改为符合目标类型的范围,或将目标更改为更大的数值类型(CS0031)。 编译器无法隐式缩小不适合的常量,例如,分配给 256byte (范围 0–255)会产生此错误。 如果截断是有意的,请在 unchecked 的上下文中使用显式强制转换。
  • 更正常量表达式中的算术,以便结果符合目标类型,或者在 unchecked 上下文中包装表达式以允许无提示溢出(CS0220)。 默认情况下,编译器在已检查的上下文中计算整个常量表达式,因此超出类型范围的中间或最终结果会导致此错误。
  • 更改常量值或目标类型以确保转换有效;如果您有意希望得到截断的结果,请将表达式包装在 unchecked 上下文中(CS0221)。 与 CS0220 不同,此错误适用于源值不适合目标类型的显式常量转换。
  • 简化或分离decimal常量表达式,使其保持在类型(decimal)的范围和精度范围内。 该 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 ,但适用于算术运算而不是转换,编译器检测到该操作可能在运行时溢出。