針對運算子宣告和溢位的錯誤和警告進行解決。

本文涵蓋下列編譯器錯誤和警告:

  • CS0031: 恆定值的「值」無法轉換成「型態」
  • CS0056:不一致的可存取性:傳回類型 'type' 的可存取性不如運算子 'operator'
  • CS0057:不一致的存取性:參數類型 'type' 的存取層級比運算子 'operator' 更低
  • CS0215:運算子 True 或 False 的傳回類型必須是布爾值
  • CS0216:運算子 'operator' 需要同時定義相應的運算子 'missing_operator'
  • CS0217: 若要套用為短路運算子,使用者定義的邏輯運算子 ('operator') 必須具有與其 2 個參數類型相同的傳回類型。
  • CS0218: 類型 ('type') 必須包含運算子 true 和運算子 false 的宣告
  • CS0220: 操作在檢查模式下於編譯時發生溢位
  • CS0221: 常數值「value」無法轉換為「類型」(使用「unchecked」語法來覆蓋)
  • CS0448:運算子++或--的傳回類型必須為包含類型或是從包含類型衍生而來
  • CS0463: 十進位常數表達式的評估失敗,錯誤為「錯誤」
  • CS0543:「 列舉」:列舉器值太大,無法放入其類型
  • CS0552:「轉換程式」:使用者定義的轉換例程至/從介面
  • CS0553:「 轉換常式」:使用者定義的轉換至/從基類轉換
  • CS0554:「轉換例程」:使用者定義的至/從衍生類別的轉換
  • CS0555: 使用者定義運算子無法採用封閉類型的物件,並轉換成封閉類型的物件
  • CS0556: 使用者定義的轉換必須轉換成封閉類型或從封閉類型轉換
  • CS0557: 類型中重複的使用者定義轉換
  • CS0558: 使用者定義運算子必須宣告為靜態和公用
  • CS0559:++或--運算子的參數類型必須是封閉類型
  • CS0562: 一元運算子的參數必須是包含類型
  • CS0563: 二進位運算子的其中一個參數必須是包含類型
  • CS0564: 多載移位運算子的第一個運算元必須與包含類型具有相同的類型,而第二個運算元的類型必須是 int
  • CS0567: 介面不能包含運算子
  • CS0590: 使用者定義運算子無法傳回 void
  • CS0594: 浮點常數超出類型「類型」範圍
  • CS0652: 與整數常數比較無用;常數超出類型「類型」範圍
  • CS0659:「 class」會覆寫 Object.Equals(object o),但不會覆寫 Object.GetHashCode()
  • CS0660:類型定義operator ==或operator !=但没有覆寫Object.Equals(object o)
  • CS0661:類型定義operator ==或operator !=但未覆寫Object.GetHashCode()
  • CS0715: 靜態類別不能包含使用者定義的運算子
  • CS1021: 積分常數太大
  • CS1037: 預期可重載運算子
  • CS1553: 宣告無效,請使用 '修飾子 <dest-type> (...' 代替
  • CS8930:使用者 定義運算子的明確實作必須宣告為靜態
  • CS8931:介面 中的使用者自訂轉換必須將外包型態的參數轉換為或從受限於該外包型別的型別參數
  • CS8778:常數值「value」在執行時可能會超出「型別」的範圍(使用「unchecked」語法來覆蓋)
  • CS8761: 運算子 'operator' 無法套用至 'default' 和類型為 'type' 的運算元,因為它是尚未確定為參考型別的型別參數
  • 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:下列成員之間的運算子解析不明確。
  • CS8761: 運算子 'operator' 無法套用至 'default' 和類型為 'type' 的運算元,因為它是無法得知是否為參考型別的型別參數

每種運算元類型都有語言規範中定義的特定參數與回傳類型需求。 關於哪些運算元可以被超載的完整規則,請參見 C# 規範中的運算子過載與運算子。

  • 將 ++ 或 -- 運算子的回傳類型變更為其所屬型別或其衍生型別(CS0448)。 該語言要求遞增與遞減運算子回傳與包含型別相容的值,以便結果能被指派回同一變數。
  • 將++或--運算子的參數改為其包含的型態(CS0559)。 增量與遞減運算子必須在自身類型的實例上運作。
  • 將一元運算子的參數改為包含的類型(CS0562)。 一元運算子必須接受宣告該運算子的類型的運算元。
  • 確保至少有一個二元運算子的參數是包含的類型(CS0563)。 二元運算子必須包含宣告型別,以便編譯器能透過該型別解析。
  • 將移位運算子的第一個參數改為包含的類型,第二個參數改為 int (CS0564)。 該語言定義了具有特定特徵的移位運算子:被移位的類型與整數移位數值。
  • 將運算子宣告從介面移到類別或結構體(CS0567)。 傳統(非靜態抽象)運算子宣告在介面中不被允許。 關於介面中的靜態抽象運算子,請參見 靜態抽象與虛擬介面成員錯誤。
  • 將運算符的回傳類型改為非空值型(CS0590)。 大多數使用者定義的運算子必須回傳一個值。 例外的是複合指派運算子,這類運算子需要一個 void 回傳型別(CS9310)。
  • 修正參數類型或新增缺少的運算子重載,使編譯器能找到與呼叫站(CS9340、 CS9341)操作數類型的匹配操作符。 當沒有適用的運算子時,編譯器會顯示最接近的候選者來協助診斷不匹配。
  • 在呼叫現場加入明確的投射,或提供更具體的超載,以消除多個操作員過載匹配度相同的歧義(CS9342)。
  • 在型態參數中加入 class、 struct、 或其他型別約束,使編譯器能判斷該表達式(default)適用的運算子。 當型別參數不受約束時,編譯器無法判斷是 default 代表 null (參考型別)還是零值型別,導致二元運算子解析模糊。 或者,避免直接在 default 具有無限制泛型類型的二進位表達式中使用。

這很重要

靜態二進位運算子和對應的實例複合賦值運算子的簽章需求是不同的。 請確定簽名與您想要的聲明相符。

運營商聲明要求

  • CS0558: 使用者定義運算子必須宣告為靜態和公用。
  • CS0715: 靜態類別不能包含使用者定義的運算子。
  • CS1037: 預期可多載運算子。
  • CS1553: 宣告無效; 請改用 '修飾運算子 <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)。 型別與其基底類別之間的轉換已透過隱含引用轉換(upcast)和明確引用轉換(downcast)存在,因此使用者定義的轉換會造成歧義。
  • 移除可將衍生類別轉換來或去的轉換運算子(CS0554)。 與基底類別轉換類似,型別與其衍生型別之間的轉換是透過繼承內建於語言中,使用者定義的轉換會與這些類型產生衝突。
  • 移除將包圍型別轉換成自身的轉換運算符(CS0555)。 每個型別本身就有隱含的身份轉換,因此使用者定義的型別轉換是冗餘且不允許的。
  • 在轉換運算子中更改其中一種類型,使其中的一個類型(來源或目的)成為外圍類型(CS0556)。 使用者定義的轉換必須包含宣告它的類型——你不能在第三個類型中定義兩個無關外部類型之間的轉換。
  • 移除重複轉換運算子,或更改其中一個重複運算子,使來源與目的節點類型不同(CS0557)。 一個型別只能對任意一對來源型別與目的型別宣告一個隱含轉換與一個顯式轉換。

布林運算子和短路運算子

  • CS0215: 運算子 true 或 false 的傳回類型必須是 bool。
  • CS0216: 運算子也需要定義相符的運算子。
  • CS0217: 為了套用為短路運算子,使用者定義的邏輯運算子必須具有與其 2 個參數類型相同的傳回類型。
  • CS0218: 類型必須包含運算子 true 和運算子 false 的宣告。

C# 語言需要特定的配對和簽章來運用於布爾運算子和短路求值。 完整規則請參閱 C# 規範中的 真與假運算子、 布林邏輯運算子,以及 使用者定義的條件邏輯運算子 。

  • 將 和 的回傳類型operator trueoperator 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: 意外關鍵字「未勾選」

checked和 unchecked 關鍵字只能套用於特定的運算子宣告。 完整規則請參閱 C# 語言規範中的 算術運算子 與 運算子 。

  • 移除不支援的運算子中的 checked 或 unchecked 關鍵字(CS9023,CS9024)。 只有算術運算子 +、 -、 *、 /++、 ,--以及顯式轉換運算子支援檢查與未檢查的變體。 其他運算子,如比較運算子或等號運算子,則沒有明顯的溢位行為,無法標記為已檢查或取消檢查。
  • 新增一個相符且未檢查的運算子版本(CS9025)。 運算 checked 子提供溢位拋出行為,但編譯器也需要對應的未檢查版本,以便在上下文中使用 unchecked ,且當兩個上下文都未指定時,作為預設使用。
  • 將關鍵字從無效位置(unchecked)移除。 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 !=)時,新增的覆寫。 像 CS0659 一樣,你需要 GetHashCode 在等號語意上保持一致。 如果 operator == 將兩個物件視為相等,但它們回傳不同的雜湊碼,基於雜湊的集合就無法正常運作。

溢出與下溢錯誤

  • CS0031: 恆定值的「值」無法轉換成「型態」
  • CS0220: 在檢查模式下,操作在編譯時溢位
  • CS0221: 常數值的「value」無法轉換成「型別」(使用「未勾選」語法來覆寫)
  • CS0463: 十進位常數表達式的評估失敗,錯誤為「錯誤」
  • CS0543:「 列舉」:列舉器值太大,無法放入其類型
  • CS0594: 浮點常數超出類型「類型」範圍
  • CS0652: 與整數常數比較無用;常數超出類型「類型」範圍
  • CS1021: 積分常數太大
  • CS8778: 常數值「value」在執行時可能會溢出「型別」(使用「unchecked」語法來覆蓋)
  • CS8973: 操作可能在執行時溢位(使用「未勾選」語法來覆蓋)

編譯器會在編譯時評估常數表達式,當值超過目標型別的有效範圍時,會回報錯誤或警告。 完整規則請參見 已檢查與未檢查語句 及 積分型別。

  • 將常數值改為符合目標類型範圍的,或將目標改為較大的數值類型(CS0031)。 編譯器無法隱含地縮小不符合條件的常數,例如,將256指派給byte(範圍 0–255)時就會產生此錯誤。 如果截斷是有意為之,請在 unchecked 語境中使用明確的轉型。
  • 修正常數表達式中的算術,使結果符合目標類型,或將表達式包裹在 未檢查 的上下文中,以允許靜默溢位(CS0220)。 編譯器預設會在編譯時以已檢查的上下文評估整個常數運算式,因此超出型別範圍的中間或最終結果會造成此錯誤。
  • 改變常數值或目標型別,使轉換有效,或者如果您有意得到截斷結果,可以用 unchecked 上下文包裹該表達式(CS0221)。 與 CS0220 不同,此錯誤適用於明確的常數轉換,當來源值不符合目的類型時。
  • 簡化或拆分decimal常數表達式,以使其保持在decimal型別的範圍和精度之內()。 該 decimal 型別的最大值約為 $7.9 \ 乘以 10^{28}$,且有 28–29 位有效位數,編譯器會在編譯時評估完整表達式。
  • 將列舉成員值改為符合列舉底層型別的值,或將底層型別改為更大的整數型別(CS0543)。 預設情況下,列舉使用 int 作為底層類型。 若成員值超過底層型別的範圍,則指定較大型別,如 long。
  • 將浮點常數改為目標型別範圍內的值,或使用更高精度的型別,例如 double 代替 float (CS0594)。 此 float 類型可達約 $3.4 乘以 10^{38}$ 的金額,並 double 支援約 $1.7 × 乘以 10^{308}$ 的金額。
  • 移除或修正比較,使常數在變數型別範圍內(CS0652)。 例如,將變數byte與300比較永遠不會成立,因此編譯器會警告這種比較是無用的。 此警告通常表示變數類型與預期值範圍間存在邏輯錯誤或不符。
  • 使用較大的數值型別,或將值拆分至多個操作(CS1021)。 當整數字面值超過最大整數型態的範圍時,會發生此誤差(ulong最高可達$1.8 × 乘以10^{19}$)。 對於超出該範圍的值,請考慮使用 BigInteger。
  • 將表達式包裹在上下文 unchecked 中以抑制警告,或將值改為符合目標類型範圍(CS8778)。 此警告表示持續轉換,執行時可能會遺失資料——編譯器無法證明溢位一定會發生,但能識別風險。
  • 將表達式包裹在上下文 unchecked 中以抑制警告,或重新結構算術以避免潛在溢出(CS8973)。 此警告類似 CS8778 ,但適用於算術運算而非轉換——編譯器偵測該操作可能在執行時溢位。