首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# out 與 ref 參數修飾詞完整差異解析與使用場景指南

     編輯:關於C#

ref 與 out 都讓方法能修改呼叫端變數的值 (傳址語義),但**初始化要求、編譯器強制規則、適用場景**有本質差異。本文透過 IL 層面解析、編譯器規則、最佳實務全方位比較。

核心差異速查表

特性refout
呼叫端變數初始化必須 在呼叫前明確指派不需要 (但必須已宣告)
方法內部讀取參數允許 (可讀取初始值)禁止 (CS0269 編譯錯誤) 必須先指派
方法內部指派要求可選 (可不修改)強制 在所有路徑返回前必須指派 (CS0177)
IL 指令ldarg.1 / stind.ref (Managed pointer)同 ref,CLR 層面無差異,差異在編譯器驗證
多載解析視為不同簽名,可與 out 共存同左
遞迴/重入安全性較低 (可讀取未初始化記憶體? 不,已初始化)較高 (編譯器保證寫入後才可讀)

程式碼示範

ref 範例:雙向資料流 (讀取初始值、修改回傳)


public void Increment(ref int value)
{
    Console.WriteLine($"Before: {value}"); // 允許讀取
    value++;
    Console.WriteLine($"After: {value}");
}

// 呼叫端
int num = 10; // 必須初始化
Increment(ref num);
Console.WriteLine(num); // 11

out 範例:單向輸出 (嘗試解析、多重回傳)


public bool TryParseInt(string input, out int result)
{
    // result = 0; // 若解析失敗仍需指派預設值
    return int.TryParse(input, out result); // 直接傳遞 out
}

// 呼叫端
if (TryParseInt("123", out int parsed))
    Console.WriteLine(parsed); // 123
// parsed 在此作用域可用 (C# 7+)

out 多重回傳經典模式


public void SplitPath(string fullPath, out string directory, out string fileName)
{
    int idx = fullPath.LastIndexOfAny(new[] { '\\', '/' });
    if (idx >= 0)
    {
        directory = fullPath.Substring(0, idx + 1);
        fileName = fullPath.Substring(idx + 1);
    }
    else
    {
        directory = "";
        fileName = fullPath;
    }
}

// 呼叫
SplitPath(@"C:\Data\File.txt", out string dir, out string name);
// dir = "C:\Data\", name = "File.txt"

進階:in 參數 (C# 7.2+) - 唯讀傳址


public void ReadOnlyLargeStruct(in BigStruct data)
{
    // data 為 readonly,任何寫入嘗試編譯錯誤
    // 避免大型結構體複製開銷,又保證不修改
    Console.WriteLine(data.SomeField);
}
  • in = ref readonly:傳址但禁止修改,適用於**大型 readonly struct** 避免防禦性複製。
  • 搭配 readonly struct 使用效果最佳。

效能真相

  • CLR 層面完全相同:ref/out/in 皆為 Managed Pointer (&),零複製、零配置。
  • 值型別:傳址避免複製結構體 (特別是 >16 bytes),效能提升明顯。
  • 參考型別:傳遞「參考的參考」 (T&),允許修改呼叫端的參考指向 (如 ref List<T> 可指向新 List)。
  • 避免濫用:參考型別本身已是傳址,ref class 只在需「換掉整個物件」時使用。

最佳實務決策樹

  1. 需**修改呼叫端變數指向** (換新物件/結構體) → ref
  2. 需**多重回傳值** (TryParse 模式、分解結果) → out
  3. 需**避免大型結構體複製**且**不修改** → in (C# 7.2+)
  4. 單純讀寫參考型別欄位/屬性 → **不加修飾詞** (預設傳參考)

常見錯誤

  • out int x; Method(out x); → x 未宣告 (需 int x; 或 out int x 內嵌宣告 C# 7+)
  • ref int x; Method(ref x); → x 未初始化 (需 int x = 0;)
  • 在 out 方法中讀取參數未先指派 → CS0269
  • out 方法有路徑未指派參數 → CS0177
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved