ความแตกต่างสรุป
| คุณสมบัติ | ref | out |
| ทิศทางข้อมูล | In/Out (Two-way) | Out Only (One-way) |
| Initialization ก่อนส่ง | บังคับ ต้อง Initialize ก่อน | ไม่ต้อง Initialize |
| Assignment ใน Method | Optional (อ่าน/เขียนได้) | บังคับ ต้อง Assign ทุก Path |
| วัตถุประสงค์ | Modify Existing Variable | Return Additional Values |
| Overload Resolution | แยกจาก out | แยกจาก ref |
ref - Reference Parameter
void Modify(ref int x)
{
Console.WriteLine($"Before: {x}"); // อ่านค่าเดิมได้
x = 20; // แก้ไขค่า Caller
}
int a = 10; // ต้อง Initialize
Modify(ref a);
Console.WriteLine($"After: {a}"); // 20
out - Output Parameter
void GetValues(out int x, out int y)
{
// x, y ยังไม่มีค่า (Unassigned)
// Console.WriteLine(x); // ❌ Error: Use of unassigned out parameter
x = 10; // บังคับ Assign
y = 20; // บังคับ Assign
}
GetValues(out int a, out int b); // ไม่ต้อง Initialize ก่อน
Console.WriteLine($"{a}, {b}"); // 10, 20
ตัวอย่าง Try Pattern (out)
bool TryParseInt(string input, out int result)
{
return int.TryParse(input, out result);
}
// Usage
if (TryParseInt("123", out int value))
{
Console.WriteLine($"Parsed: {value}");
}
else
{
Console.WriteLine("Invalid number");
}
ตัวอย่าง ref (Swap)
void Swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
int x = 1, y = 2;
Swap(ref x, ref y);
Console.WriteLine($"{x}, {y}"); // 2, 1
ref return & ref local (C# 7+)
int[] numbers = { 1, 2, 3, 4, 5 };
// Return Reference to Array Element
ref int FindFirstEven(int[] arr)
{
for (int i = 0; i < arr.Length; i++)
{
if (arr[i] % 2 == 0)
return ref arr[i]; // Return Reference
}
throw new InvalidOperationException();
}
// Usage
ref int evenRef = ref FindFirstEven(numbers);
evenRef = 100; // Modify Array Element Directly!
Console.WriteLine(numbers[1]); // 100
in Parameter (C# 7.2+) - Read-only Reference
void ReadOnly(in BigStruct data)
{
// data.X = 10; // ❌ Compile Error: Cannot assign to 'in' parameter
Console.WriteLine(data.X); // ✅ Read OK
}
// ใช้กับ Struct ใหญ่ หลีกเลี่ยง Copy
readonly struct BigStruct
{
public long A, B, C, D, E, F, G, H;
}
void Process(in BigStruct s) { } // Pass by Ref, No Copy
Method Overloading: ref vs out
class Demo
{
public void Method(ref int x) { } // Overload 1
public void Method(out int x) { } // Overload 2 (Valid - Different Signature)
// public void Method(int x) { } // Overload 3 (Valid)
}
// Call
int a = 0;
demo.Method(ref a); // Calls ref version
demo.Method(out a); // Calls out version
Best Practice
- ✅ ใช้
out สำหรับ Try Pattern, Multiple Return Values
- ✅ ใช้
ref สำหรับ Swap, Modify Caller Variable, Performance (Large Struct)
- ✅ ใช้
in สำหรับ Read-only Large Struct Parameter
- ✅ ใช้ Tuple/Record แทน out/ref สำหรับ General Multiple Returns
- ❌ หลีกเลี่ยง ref/out ใน Public API (Complexity, Confusion)
- ❌ อย่าใช้ ref/out กับ Async Methods (ไม่รองรับ)