與傳址參數、變數和傳回相關聯的錯誤和警告

處理參考變數時,可能會產生下列錯誤:

  • CS0192readonly 欄位不能作為 refout 值 (在建構函式中除外)
  • CS0199static readonly 欄位不能作為 refout 值 (在靜態建構函式中除外)
  • CS0206不傳回 ref 的屬性或索引子不得作為 outref
  • CS0631refout 在此內容中無效
  • CS0767無法繼承具有指定型別參數的介面,因為這會讓方法包含僅 refout 有所差異的多載
  • CS1510refout 值必須是可指派的變數
  • CS1605無法使用變數作為 refout 值,因為它是唯讀
  • CS1623迭代器不能有 refinout 參數
  • CS1649readonly 欄位的成員不能作為 refout 值 (在建構函式中除外)
  • CS1651靜態唯讀欄位的欄位不能作為 refout 值 (在建構函式中除外)
  • CS1655無法將型別為 refout 的欄位用作值
  • CS1657無法使用變數作為 refout
  • CS1741refout 參數不能有預設值
  • CS1939無法將範圍變數當作 outref 參數傳遞
  • CS1988非同步方法不能有 refinout 參數
  • CS7084Windows 執行階段事件不能當作 outref 參數傳遞。
  • CS8196不允許在同一個引數清單中參考隱含型別的 out 變數。
  • CS8325在包含 ref 條件運算子的運算式中,不可使用 'await'
  • CS8326這兩個條件運算子的值都必須是 ref 值,或兩個都不是 ref 值
  • CS8327運算式必須為正確型別,才能符合替代 ref 值
  • CS8329無法使用變數作為 refout 值,因為它是唯讀變數
  • CS8330變數的成員無法作為 refout 值,因為它是唯讀變數
  • CS8331無法指派給變數,或將其用在 ref 指派的右側,因為它是唯讀變數
  • CS8332無法指派給變數的成員,或將其用在 ref 指派的右側,因為它是唯讀變數
  • CS8337 'ref' 擴充方法的第一個參數必須是限制為結構的實值型別或泛型型別。
  • CS8338擴充方法的第一個 'in' 或 'ref readonly' 參數必須是實體 (非泛型) 實值型別。
  • CS8373ref 指派的左側必須為 ref 變數。
  • CS8388out 變數不可宣告為 ref local
  • CS8977無法在具有 'UnmanagedCallersOnly' 屬性的方法簽章中使用 'ref'、'in' 或 'out'。
  • CS8986參數的「範圍化」修飾符與目標不符。
  • CS8987參數的「scoped」修飾符與覆寫或實作的成員不匹配。
  • CS9061「scoped」修飾符無法與 「discard」一起使用。
  • CS9062類型與別名不能被命名為「作用範圍」。
  • CS9063UnscopedRefAttribute 無法套用於此參數,因為它預設是無作用域的。
  • CS9065請勿使用 'System.Runtime.CompilerServices.ScopedRefAttribute'。改用「scoped」關鍵字。
  • CS9066UnscopedRefAttribute 無法套用在帶有「scoped」修飾符的參數上。
  • CS9072解構變數不可宣告為 ref local
  • CS9101UnscopedRefAttribute 只能套用於結構或虛擬介面的執行個體方法和屬性,且不能套用於建構函式或僅限 init 的成員。
  • CS9102UnscopedRefAttribute 無法套用至介面實作,因為實作的成員沒有此屬性。
  • CS9104無法在非同步方法或非同步 Lambda 運算式中使用類型為 using 的 statement 資源。
  • CS9190必須在 readonly 之後指定 ref 修飾元。
  • CS9199ref readonly 參數不能有 Out 屬性。

當參考變數使用不正確時,就會產生下列警告:

  • CS9073參數的「範圍化」修飾符與目標不符。
  • CS9074參數的「scoped」修飾符與覆載或實作的成員不符。
  • CS9191對應至 ref 參數之引數的 in 修飾元相當於 in。請考慮改用in
  • CS9192引數應該與 refin 關鍵字一起傳遞。
  • CS9193引數應該是變數,因為它會傳遞至 ref readonly 參數
  • CS9195引數應該與 in 關鍵字一起傳遞
  • CS9196參數的參考類型修飾元不符合已覆寫或實作成員中的對應參數。
  • CS9197參數的參考類型修飾元不符合隱藏成員中的對應參數。
  • CS9198參數的參考類型修飾元不符合目標中的對應參數。
  • CS9200已指定 ref readonly 參數的預設值,但 ref readonly 只應用於參考。考慮將參數宣告為 in
  • CS9201ref 欄位應在使用前先以 ref 指派。
  • CS9265欄位從未被以 ref 指派,因此一律會維持其預設值(null 參考)

這些錯誤和警告會遵循下列主題:

本文使用參考變數一詞做為使用其中一個 inref readonlyrefout 修飾元,或 ref 區域變數、ref 中的 ref struct 欄, 或 ref 傳回宣告之參數的一般詞彙。 參考變數會參考另一個變數,稱為參照

語法不正確

這些錯誤表示您使用的參考變數語法不正確:

  • CS8373ref 指派的左側必須為 ref 變數。
  • CS8388out 變數不可宣告為 ref local。
  • CS9190必須在 readonly 之後指定 ref 修飾元。

為了更正這些錯誤:

  • 確保 = ref 運算子的左操作數為引用變數,而不是值表達式或非參考區域變數。 參考指派要求雙方皆為可建立與同一儲存位置的別名(CS8373)的參考變數。
  • 宣告參考參數時,將修飾符寫成 而 ref readonlyreadonly ref。 C# 語言規範要求 ref 關鍵字必須置 readonly 於參數宣告前的修飾符,以維持所有參考參數類型語法一致(CS9190)。
  • 在宣告局部參考變數時,請使用關鍵字 ref 代替 outout 是唯一一個參數修飾符,表示方法必須指派一個值才能回傳,而 ref 則是建立區域變數以別名其他儲存位置的適當關鍵字(CS8388)。 欲了解更多關於參考變數及其語法要求的資訊,請參閱 參考變數C# 語言規範

參考變數限制

下列錯誤表示參考變數不能用於您有參考變數的位置:

  • CS0631refout 在此內容中無效
  • CS0767無法繼承具有指定型別參數的介面,因為這會讓方法包含僅 refout 有所差異的多載
  • CS1623迭代器不能有 refinout 參數
  • CS1741refout 參數不能有預設值
  • CS1939無法將範圍變數當作 outref 參數傳遞
  • CS1988非同步方法不能有 refinout 參數
  • CS7084Windows 執行階段事件不能以 outref 參數形式傳遞。
  • CS8196不允許在相同引數清單中參考隱含型別 out 變數。
  • CS8325包含 ref 條件運算子的運算式無法使用 'await'
  • CS8326這兩個條件運算子的值都必須是 ref 值,或兩個都不是 ref 值
  • CS8327運算式必須為正確型別,才能符合替代 ref 值
  • CS8337'ref' 擴充方法的第一個參數必須是限制為結構的實值型別或泛型型別。
  • CS8338擴充方法的第一個 'in' 或 'ref readonly' 參數必須是實體 (非泛型) 實值型別。
  • CS8977無法在具有 'UnmanagedCallersOnly' 屬性的方法簽章中使用 'ref'、'in' 或 'out'。
  • CS9072解構變數不可宣告為 ref local
  • CS9104類型為 using 的陳述式資源不可在非同步方法或非同步 Lambda 運算式中使用。
  • CS9199ref readonly 參數不能有 Out 屬性。

下列警告指出不應該使用參考變數,而且可能不安全:

  • CS9196參數的參考類型修飾元不符合已覆寫或實作成員中的對應參數。
  • CS9197參數的參考類型修飾元不符合隱藏成員中的對應參數。
  • CS9198參數的參考類型修飾元不符合目標中的對應參數。
  • CS9200已指定 ref readonly 參數的預設值,但 ref readonly 只應用於參考。考慮將參數宣告為 in
  • CS9201ref 欄位應在使用前先以 ref 指派。
  • CS9265欄位從未被以 ref 指派,因此一律會維持其預設值(null 參考)

為了更正這些錯誤:

  • 移除 索引器的參考參數。 索引器設計為提供類似陣列的存取語法,編譯器無法保證透過索引器存取器(CS0631CS1623)傳遞的參考資料能安全追蹤其生命週期。
  • 移除 迭代器方法中的參考參數。 迭代器在跨多次呼叫中使用狀態機制時,會慣性地執行程式碼,而在執行暫停和恢復的 yield return 邊界內,編譯器無法確保被引用的變數仍然有效(CS1623)。
  • 移除 非同步方法中的參考參數。 非同步方法可能會在等待點暫停執行,並在不同執行緒上繼續執行,這使得無法保證參考變數在整個執行過程中都有效且可存取(CS1988)。
  • 避免在 ref 條件式中使用 await 表達式。 等待操作可能會暫停執行,並使條件運算子選擇的參考失效,導致執行恢復時可能會使用已失效的引用(CS8325)。
  • 確保參考條件運算子的兩個分支都能回傳參考,否則兩者都不回傳參考,且當兩者都是參考時,必須是相同類型。 條件運算子必須產生一個一致的結果類型,無論選擇哪個分支,呼叫碼都能安全使用(CS8326CS8327)。
  • 移除 refout 參數中的預設值。 參考參數必須在呼叫站點提供,以建立參數與現有變數之間的必要別名關係,使預設值在語意上失去意義(CS1741)。
  • 避免在參數列表中宣告隱式型別 out 的變數,並且在列表中引用該變數。 編譯器必須從方法簽名推斷變數型別,同時驗證該變數在同一表達式中的使用,形成循環依賴關係(CS8196)。
  • 不要把 LINQ 查詢 範圍變數當作參考參數傳遞。 範圍變數是由編譯器產生的迭代變數,其壽命由查詢執行模型管理,且沒有可安全引用的穩定記憶體位置(CS1939)。
  • 解構物件時,請使用常規值變數代替 ref 本地變數。 解構會建立新變數來接收解構後的值,參考變數會嘗試將這些暫時值別名,而非獨立儲存(CS9072)。
  • 避免實作多個介面,其方法僅因參數上的 refout 修飾符不同。 C# 語言規範將這些視為不同的簽章,但並未提供消除歧義的方式來辨識應呼叫哪個實作,因為 ref 兩者 out 在實作邊界共享相同的呼叫語法(CS0767)。
  • 移除裝飾為 System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute的方法中的參考參數。 這些方法可從不支援 C# 參考安全規則且無法保證參考變數在受控/非受控邊界間的適當生命週期管理(CS8977)的非受控程式碼中呼叫。
  • ref的參數上,僅對值型別或受限於值型別的通用型別使用修飾符。 參考型別已在 CLR 層級透過引用傳遞,新增 ref 會產生指向某個參考,而帶有 ref 的值型別擴充則可實現擴充實例的變異(CS8337CS8338)。
  • 不要把 Windows 執行時事件當作參考參數傳遞。 這些事件遵循 Windows 執行階段型別系統,具有與 .NET 參考不同的生命週期及執行緒語意,且不支援 C# 參考參數(CS7084)所需的別名行為。
  • 移除System.Runtime.InteropServices.OutAttributeref readonly 參數。 此屬性設計用於需要編組語義且參數僅以輸出為方向的平台調用情境中,這與ref readonly的保證相衝突,即參數所引用的現有資料不會被重新指派(CS9199)。
  • 確保該型別中的所有 ref 欄位在欄位初始化器或所有建構子程式碼路徑中都已指派,且建構子尚未完成。 未初始化的參考欄位會包含無效的參考,若被存取可能導致記憶體損毀(CS9201CS9265)。
  • 將方法與其覆寫的基礎方法或實作介面方法之間的參考種類修飾符refinoutref readonly相匹配。 參考修飾符是方法簽章合約的一部分,衍生型別必須遵守此契約,以維持可替換性及呼叫者期望(CS9196CS9197CS9198)。
  • 在提供預設值時,應宣告參數為 而 inref readonlyref readonly 設計用於呼叫者將參考傳遞給現有變數,而 in 參數可接受參考與暫存的值副本,使預設值具有意義(CS9200)。

關於允許使用參考變數的更多資訊,請參閱 方法參數迭代器、 非同步程式設計模式C# 語言規範

unscoped ref 限制

在某些位置,不允許使用於 ref 參數上的 unscoped 限定詞:

  • CS9101UnscopedRefAttribute 只能套用於結構體實例或虛擬介面的方法與屬性,無法套用於建構子或僅初始化的成員。
  • CS9102UnscopedRefAttribute 無法套用到介面實作,因為實作成員沒有此屬性。

為了更正這些錯誤:

  • 從結構建構子和僅初始化的成員中移除 unscoped 修飾符或 System.Diagnostics.CodeAnalysis.UnscopedRefAttribute 屬性。 這些成員有特殊的初始化語意,編譯器必須確保任何參考不會超過初始化階段,且允許無作用域的引用將違反初始化完成後結構體完全可存取的保證(CS9101)。
  • 當對應的介面方法沒有修飾符時,從介面實作方法中移除 unscoped 修飾符。 未作用範圍特性會影響方法關於參考壽命保證的合約,實作必須維持與所實作介面相同的合約,以確保呼叫者無論呼叫哪種實作都能依賴一致的生命週期行為(CS9102)。

欲了解更多有關有作用域與非作用域參考的資訊,請參閱 C# 語言規範中的 方法參數安全上下文約束

參考變數需要參照

您必須提供變數作為參考參數、參考傳回或 ref 區域變數指派的引數:

  • CS0206非 ref 傳回的屬性或索引子不能作為 outref 值使用
  • CS1510refout 值必須是可指派的變數

警告:

  • CS9191對應至 ref 參數之引數的 in 修飾元相當於 in。請考慮改用 in
  • CS9192引數應該與 refin 關鍵字一起傳遞。
  • CS9193引數應該是變數,因為它會傳遞至 ref readonly 參數
  • CS9195引數應該與 in 關鍵字一起傳遞

為了更正這些錯誤:

  • 將屬性或索引器存取的結果存於本地變數中,再將其作為參考參數傳遞。 屬性索引器 是回傳數值的方法,而非直接存取儲存位置,而參考參數則需要具備穩定記憶體位置且可混淆的變數(CS0206CS1510)。
  • 在傳遞參數給in參數時,請使用ref修飾符代替in。 雖然 ref 技術上因向下相容而可行,但修 in 飾符更明確表達參數唯讀的意圖,且可更有效率地作為參考傳遞而無需複製(CS9191CS9195)。
  • 在將參數傳遞給預期有參考的參數時,加入適當的參考修飾符(refin, 或 ref readonly)。 省略修飾符可能導致編譯器建立該值的暫存副本,這效率低落,且若呼叫程式碼預期修改會反映在原始變數中,可能導致意外行為(CS9192CS9193)。

欲了解更多關於參考參數及透過參考傳遞變數的資訊,請參閱 方法參數ref 關鍵字C# 語言規範

可寫入參考變數需要可寫入的參照

可寫入的參考變數要求其所參照的對象也必須是可寫入的。 下列錯誤表示變數不可寫入:

  • CS0192readonly 欄位不能作為 refout 值 (在建構函式中除外)
  • CS0199static readonly 欄位不能作為 refout 值 (在靜態建構函式中除外)
  • CS1605無法使用變數作為 refout 值,因為它是唯讀
  • CS1649readonly 欄位的成員不能作為 refout 值 (在建構函式中除外)
  • CS1651static readonly 欄位的成員欄位不可當作 refout 值使用(靜態建構函式中除外)
  • CS1655無法將某型別的欄位用作 refout
  • CS1657無法使用變數作為 refout
  • CS8329無法使用變數作為 refout 值,因為它是唯讀變數
  • CS8330變數的成員無法作為 refout 值,因為它是唯讀變數
  • CS8331無法指派給變數,或將其用在 ref 指派的右側,因為它是唯讀變數
  • CS8332無法指派給變數的成員,或將其用在 ref 指派的右側,因為它是唯讀變數

為了更正這些錯誤:

  • 只讀欄位 的值複製到本地變數,並將當地變數作為 ref or out 參數傳遞。 可讀欄位在初始化後是不可變的(建構子內除外),允許可寫的引用會違反可讀欄位所提供的不可變性保障(CS0192CS0199CS1649CS1651)。
  • 當你需要透過參考傳遞唯讀變數、迭代變數或其他不可寫入的值時,請使用 ref readonlyin 參數來代替 refout。 這些修飾符表示方法只會讀取參考值,且不會嘗試修改它。 這與原始變數的不可變性約束(CS1605CS1655CS1657CS8329)相符。
  • 在將可寫變數作為可寫參考傳遞前,先將唯讀變數的成員複製到本地變數。 即使成員本身可能未被宣告為可讀,但它仍透過可讀路徑(透過可讀欄位、 in 參數或 ref readonly 本地)存取,編譯器會強制可讀性傳遞,以防止可讀資料的間接變異(CS8330CS8332)。
  • 避免對只讀變數、 每次迭代變數使用語句資源固定語句變數進行可寫的引用指派。 這些變數具有由編譯器管理的特殊終身語意。 變數在其作用域結束時會自動被最終定值或丟棄。 外部引用會在處置後產生懸掛的參考(CS8331)。

欲了解更多關於唯讀語意與參考參數的資訊,請參閱參數修飾符中的可讀關鍵字ref readonly 以及 C# 語言規範