處理參考變數時,可能會產生下列錯誤:
-
CS0192:
readonly欄位不能作為ref或out值 (在建構函式中除外) -
CS0199:
static readonly欄位不能作為ref或out值 (在靜態建構函式中除外) -
CS0206:不傳回 ref 的屬性或索引子不得作為
out或ref值 -
CS0631:
ref和out在此內容中無效 -
CS0767:無法繼承具有指定型別參數的介面,因為這會讓方法包含僅
ref和out有所差異的多載 -
CS1510:
ref或out值必須是可指派的變數 -
CS1605:無法使用變數作為
ref或out值,因為它是唯讀 -
CS1623:迭代器不能有
ref、in或out參數 -
CS1649:
readonly欄位的成員不能作為ref或out值 (在建構函式中除外) -
CS1651:靜態唯讀欄位的欄位不能作為
ref或out值 (在建構函式中除外) -
CS1655:無法將型別為
ref或out的欄位用作值 -
CS1657:無法使用變數作為
ref或out值 -
CS1741:
ref或out參數不能有預設值 -
CS1939:無法將範圍變數當作
out或ref參數傳遞 -
CS1988:非同步方法不能有
ref、in或out參數 -
CS7084:Windows 執行階段事件不能當作
out或ref參數傳遞。 - CS8196:不允許在同一個引數清單中參考隱含型別的 out 變數。
-
CS8325:在包含
ref條件運算子的運算式中,不可使用 'await' - CS8326:這兩個條件運算子的值都必須是 ref 值,或兩個都不是 ref 值
- CS8327:運算式必須為正確型別,才能符合替代 ref 值
-
CS8329:無法使用變數作為
ref或out值,因為它是唯讀變數 -
CS8330:變數的成員無法作為
ref或out值,因為它是唯讀變數 -
CS8331:無法指派給變數,或將其用在
ref指派的右側,因為它是唯讀變數 -
CS8332:無法指派給變數的成員,或將其用在
ref指派的右側,因為它是唯讀變數 -
CS8337: '
ref' 擴充方法的第一個參數必須是限制為結構的實值型別或泛型型別。 -
CS8338:擴充方法的第一個 '
in' 或 'ref readonly' 參數必須是實體 (非泛型) 實值型別。 -
CS8373:
ref指派的左側必須為 ref 變數。 -
CS8388:
out變數不可宣告為 ref local -
CS8977:無法在具有 'UnmanagedCallersOnly' 屬性的方法簽章中使用 '
ref'、'in' 或 'out'。 - CS8986: 參數的「範圍化」修飾符與目標不符。
- CS8987: 參數的「scoped」修飾符與覆寫或實作的成員不匹配。
- CS9061: 「scoped」修飾符無法與 「discard」一起使用。
- CS9062: 類型與別名不能被命名為「作用範圍」。
- CS9063: UnscopedRefAttribute 無法套用於此參數,因為它預設是無作用域的。
- CS9065: 請勿使用 'System.Runtime.CompilerServices.ScopedRefAttribute'。改用「scoped」關鍵字。
- CS9066: UnscopedRefAttribute 無法套用在帶有「scoped」修飾符的參數上。
- CS9072:解構變數不可宣告為 ref local
- CS9101:UnscopedRefAttribute 只能套用於結構或虛擬介面的執行個體方法和屬性,且不能套用於建構函式或僅限 init 的成員。
- CS9102:UnscopedRefAttribute 無法套用至介面實作,因為實作的成員沒有此屬性。
-
CS9104:無法在非同步方法或非同步 Lambda 運算式中使用類型為
using的 statement 資源。 -
CS9190:必須在
readonly之後指定ref修飾元。 -
CS9199:
ref readonly參數不能有 Out 屬性。
當參考變數使用不正確時,就會產生下列警告:
- CS9073: 參數的「範圍化」修飾符與目標不符。
- CS9074:參數的「scoped」修飾符與覆載或實作的成員不符。
-
CS9191:對應至
ref參數之引數的in修飾元相當於in。請考慮改用in。 -
CS9192:引數應該與
ref或in關鍵字一起傳遞。 -
CS9193:引數應該是變數,因為它會傳遞至
ref readonly參數 -
CS9195:引數應該與
in關鍵字一起傳遞 - CS9196:參數的參考類型修飾元不符合已覆寫或實作成員中的對應參數。
- CS9197:參數的參考類型修飾元不符合隱藏成員中的對應參數。
- CS9198:參數的參考類型修飾元不符合目標中的對應參數。
-
CS9200:已指定
ref readonly參數的預設值,但ref readonly只應用於參考。考慮將參數宣告為in。 - CS9201:ref 欄位應在使用前先以 ref 指派。
- CS9265:欄位從未被以 ref 指派,因此一律會維持其預設值(null 參考)
這些錯誤和警告會遵循下列主題:
- 不正確的語法:宣告或使用方式的語法無效。
-
語言建構,其中
ref變數無效:某些 C# 慣用語不允許變數。 這通常是因為無法可靠地進行 ref 安全分析。 - 指定的值運算式中需要參考變數:用來做為參考變數的運算式必須是變數,而不是值表達式。
- 參考到唯讀變數的可寫入參考變數:對唯讀變數的參考無法以可寫入參考傳遞。
本文使用參考變數一詞做為使用其中一個 in、ref readonly、ref 或 out 修飾元,或 ref 區域變數、ref 中的 ref struct 欄, 或 ref 傳回宣告之參數的一般詞彙。 參考變數會參考另一個變數,稱為參照。
語法不正確
這些錯誤表示您使用的參考變數語法不正確:
-
CS8373:
ref指派的左側必須為 ref 變數。 -
CS8388:
out變數不可宣告為 ref local。 -
CS9190:必須在
readonly之後指定ref修飾元。
為了更正這些錯誤:
- 確保
= ref運算子的左操作數為引用變數,而不是值表達式或非參考區域變數。 參考指派要求雙方皆為可建立與同一儲存位置的別名(CS8373)的參考變數。 - 宣告參考參數時,將修飾符寫成 而
ref readonly非readonly ref。 C# 語言規範要求ref關鍵字必須置readonly於參數宣告前的修飾符,以維持所有參考參數類型語法一致(CS9190)。 - 在宣告局部參考變數時,請使用關鍵字
ref代替out。out是唯一一個參數修飾符,表示方法必須指派一個值才能回傳,而ref則是建立區域變數以別名其他儲存位置的適當關鍵字(CS8388)。 欲了解更多關於參考變數及其語法要求的資訊,請參閱 參考變數 及 C# 語言規範。
參考變數限制
下列錯誤表示參考變數不能用於您有參考變數的位置:
-
CS0631:
ref和out在此內容中無效 -
CS0767:無法繼承具有指定型別參數的介面,因為這會讓方法包含僅
ref和out有所差異的多載 -
CS1623:迭代器不能有
ref、in或out參數 -
CS1741:
ref或out參數不能有預設值 -
CS1939:無法將範圍變數當作
out或ref參數傳遞 -
CS1988:非同步方法不能有
ref、in或out參數 -
CS7084:Windows 執行階段事件不能以
out或ref參數形式傳遞。 -
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 運算式中使用。 -
CS9199:
ref readonly參數不能有 Out 屬性。
下列警告指出不應該使用參考變數,而且可能不安全:
- CS9196:參數的參考類型修飾元不符合已覆寫或實作成員中的對應參數。
- CS9197:參數的參考類型修飾元不符合隱藏成員中的對應參數。
- CS9198:參數的參考類型修飾元不符合目標中的對應參數。
-
CS9200:已指定
ref readonly參數的預設值,但ref readonly只應用於參考。考慮將參數宣告為in。 - CS9201:ref 欄位應在使用前先以 ref 指派。
- CS9265:欄位從未被以 ref 指派,因此一律會維持其預設值(null 參考)
為了更正這些錯誤:
- 移除 索引器的參考參數。 索引器設計為提供類似陣列的存取語法,編譯器無法保證透過索引器存取器(CS0631, CS1623)傳遞的參考資料能安全追蹤其生命週期。
- 移除 迭代器方法中的參考參數。 迭代器在跨多次呼叫中使用狀態機制時,會慣性地執行程式碼,而在執行暫停和恢復的 yield return 邊界內,編譯器無法確保被引用的變數仍然有效(CS1623)。
- 移除 非同步方法中的參考參數。 非同步方法可能會在等待點暫停執行,並在不同執行緒上繼續執行,這使得無法保證參考變數在整個執行過程中都有效且可存取(CS1988)。
- 避免在 ref 條件式中使用 await 表達式。 等待操作可能會暫停執行,並使條件運算子選擇的參考失效,導致執行恢復時可能會使用已失效的引用(CS8325)。
- 確保參考條件運算子的兩個分支都能回傳參考,否則兩者都不回傳參考,且當兩者都是參考時,必須是相同類型。 條件運算子必須產生一個一致的結果類型,無論選擇哪個分支,呼叫碼都能安全使用(CS8326、 CS8327)。
- 移除
ref和out參數中的預設值。 參考參數必須在呼叫站點提供,以建立參數與現有變數之間的必要別名關係,使預設值在語意上失去意義(CS1741)。 - 避免在參數列表中宣告隱式型別
out的變數,並且在列表中引用該變數。 編譯器必須從方法簽名推斷變數型別,同時驗證該變數在同一表達式中的使用,形成循環依賴關係(CS8196)。 - 不要把 LINQ 查詢 範圍變數當作參考參數傳遞。 範圍變數是由編譯器產生的迭代變數,其壽命由查詢執行模型管理,且沒有可安全引用的穩定記憶體位置(CS1939)。
- 在解構物件時,請使用常規值變數代替 ref 本地變數。 解構會建立新變數來接收解構後的值,參考變數會嘗試將這些暫時值別名,而非獨立儲存(CS9072)。
- 避免實作多個介面,其方法僅因參數上的
ref和out修飾符不同。 C# 語言規範將這些視為不同的簽章,但並未提供消除歧義的方式來辨識應呼叫哪個實作,因為ref兩者out在實作邊界共享相同的呼叫語法(CS0767)。 - 移除裝飾為 System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute的方法中的參考參數。 這些方法可從不支援 C# 參考安全規則且無法保證參考變數在受控/非受控邊界間的適當生命週期管理(CS8977)的非受控程式碼中呼叫。
- 在
ref的參數上,僅對值型別或受限於值型別的通用型別使用修飾符。 參考型別已在 CLR 層級透過引用傳遞,新增ref會產生指向某個參考,而帶有ref的值型別擴充則可實現擴充實例的變異(CS8337、 CS8338)。 - 不要把 Windows 執行時事件當作參考參數傳遞。 這些事件遵循 Windows 執行階段型別系統,具有與 .NET 參考不同的生命週期及執行緒語意,且不支援 C# 參考參數(CS7084)所需的別名行為。
- 移除System.Runtime.InteropServices.OutAttribute 從
ref readonly參數。 此屬性設計用於需要編組語義且參數僅以輸出為方向的平台調用情境中,這與ref readonly的保證相衝突,即參數所引用的現有資料不會被重新指派(CS9199)。 - 確保該型別中的所有
ref欄位在欄位初始化器或所有建構子程式碼路徑中都已指派,且建構子尚未完成。 未初始化的參考欄位會包含無效的參考,若被存取可能導致記憶體損毀(CS9201、 CS9265)。 - 將方法與其覆寫的基礎方法或實作介面方法之間的參考種類修飾符
ref、in、out、ref readonly相匹配。 參考修飾符是方法簽章合約的一部分,衍生型別必須遵守此契約,以維持可替換性及呼叫者期望(CS9196、 CS9197、 CS9198)。 - 在提供預設值時,應宣告參數為 而
in非ref readonly。ref readonly設計用於呼叫者將參考傳遞給現有變數,而in參數可接受參考與暫存的值副本,使預設值具有意義(CS9200)。
關於允許使用參考變數的更多資訊,請參閱 方法參數、 迭代器、 非同步程式設計模式及 C# 語言規範。
unscoped ref 限制
在某些位置,不允許使用於 ref 參數上的 unscoped 限定詞:
- CS9101: UnscopedRefAttribute 只能套用於結構體實例或虛擬介面的方法與屬性,無法套用於建構子或僅初始化的成員。
- CS9102: UnscopedRefAttribute 無法套用到介面實作,因為實作成員沒有此屬性。
為了更正這些錯誤:
- 從結構建構子和僅初始化的成員中移除
unscoped修飾符或 System.Diagnostics.CodeAnalysis.UnscopedRefAttribute 屬性。 這些成員有特殊的初始化語意,編譯器必須確保任何參考不會超過初始化階段,且允許無作用域的引用將違反初始化完成後結構體完全可存取的保證(CS9101)。 - 當對應的介面方法沒有修飾符時,從介面實作方法中移除
unscoped修飾符。 未作用範圍特性會影響方法關於參考壽命保證的合約,實作必須維持與所實作介面相同的合約,以確保呼叫者無論呼叫哪種實作都能依賴一致的生命週期行為(CS9102)。
欲了解更多有關有作用域與非作用域參考的資訊,請參閱 C# 語言規範中的 方法參數 與 安全上下文約束 。
參考變數需要參照
您必須提供變數作為參考參數、參考傳回或 ref 區域變數指派的引數:
-
CS0206:非 ref 傳回的屬性或索引子不能作為
out或ref值使用 -
CS1510:
ref或out值必須是可指派的變數
警告:
-
CS9191:對應至
ref參數之引數的in修飾元相當於in。請考慮改用in。 -
CS9192:引數應該與
ref或in關鍵字一起傳遞。 -
CS9193:引數應該是變數,因為它會傳遞至
ref readonly參數 -
CS9195:引數應該與
in關鍵字一起傳遞
為了更正這些錯誤:
- 將屬性或索引器存取的結果存於本地變數中,再將其作為參考參數傳遞。 屬性 與 索引器 是回傳數值的方法,而非直接存取儲存位置,而參考參數則需要具備穩定記憶體位置且可混淆的變數(CS0206, CS1510)。
- 在傳遞參數給
in參數時,請使用ref修飾符代替in。 雖然ref技術上因向下相容而可行,但修in飾符更明確表達參數唯讀的意圖,且可更有效率地作為參考傳遞而無需複製(CS9191, CS9195)。 - 在將參數傳遞給預期有參考的參數時,加入適當的參考修飾符(
ref,in, 或ref readonly)。 省略修飾符可能導致編譯器建立該值的暫存副本,這效率低落,且若呼叫程式碼預期修改會反映在原始變數中,可能導致意外行為(CS9192、 CS9193)。
欲了解更多關於參考參數及透過參考傳遞變數的資訊,請參閱 方法參數、 ref 關鍵字及 C# 語言規範。
可寫入參考變數需要可寫入的參照
可寫入的參考變數要求其所參照的對象也必須是可寫入的。 下列錯誤表示變數不可寫入:
-
CS0192:
readonly欄位不能作為ref或out值 (在建構函式中除外) -
CS0199:
static readonly欄位不能作為ref或out值 (在靜態建構函式中除外) -
CS1605:無法使用變數作為
ref或out值,因為它是唯讀 -
CS1649:
readonly欄位的成員不能作為ref或out值 (在建構函式中除外) -
CS1651:
static readonly欄位的成員欄位不可當作ref或out值使用(靜態建構函式中除外) -
CS1655:無法將某型別的欄位用作
ref或out值 -
CS1657:無法使用變數作為
ref或out值 -
CS8329:無法使用變數作為
ref或out值,因為它是唯讀變數 -
CS8330:變數的成員無法作為
ref或out值,因為它是唯讀變數 -
CS8331:無法指派給變數,或將其用在
ref指派的右側,因為它是唯讀變數 -
CS8332:無法指派給變數的成員,或將其用在
ref指派的右側,因為它是唯讀變數
為了更正這些錯誤:
- 將 只讀欄位 的值複製到本地變數,並將當地變數作為
reforout參數傳遞。 可讀欄位在初始化後是不可變的(建構子內除外),允許可寫的引用會違反可讀欄位所提供的不可變性保障(CS0192、 CS0199、 CS1649、 CS1651)。 - 當你需要透過參考傳遞唯讀變數、迭代變數或其他不可寫入的值時,請使用
ref readonly或in參數來代替ref或out。 這些修飾符表示方法只會讀取參考值,且不會嘗試修改它。 這與原始變數的不可變性約束(CS1605、 CS1655、 CS1657、 CS8329)相符。 - 在將可寫變數作為可寫參考傳遞前,先將唯讀變數的成員複製到本地變數。 即使成員本身可能未被宣告為可讀,但它仍透過可讀路徑(透過可讀欄位、
in參數或ref readonly本地)存取,編譯器會強制可讀性傳遞,以防止可讀資料的間接變異(CS8330、 CS8332)。 - 避免對只讀變數、 每次迭代變數、 使用語句資源或 固定語句變數進行可寫的引用指派。 這些變數具有由編譯器管理的特殊終身語意。 變數在其作用域結束時會自動被最終定值或丟棄。 外部引用會在處置後產生懸掛的參考(CS8331)。
欲了解更多關於唯讀語意與參考參數的資訊,請參閱參數修飾符中的可讀關鍵字、ref readonly 以及 C# 語言規範。