ภาพรวม
Pass by Reference (การส่งอ้างอิง) ใน C# ทำให้เมธอดเข้าถึง ตัวแปรจริง (Argument) โดยตรง ไม่ได้สร้าง Copy ค่า หรือ Copy Reference การเปลี่ยนแปลงพารามิเตอร์ภายในเมธอดจะ ส่งผลต่อตัวแปรต้นฉบับ ทันที
คีย์เวิร์ด: ref
ใช้ ref ทั้งใน Signature เมธอด และตอนเรียกใช้
ตัวอย่างโปรแกรม: Swap แบบ Pass by Reference
using System;
namespace CalculatorApplication
{
class NumberManipulator
{
// ref ใน Signature
public void Swap(ref int x, ref int y)
{
int temp = x;
x = y;
y = temp;
}
static void Main(string[] args)
{
NumberManipulator n = new NumberManipulator();
int a = 100;
int b = 200;
Console.WriteLine("ก่อน Swap: a={0}, b={1}", a, b);
// ref ตอนเรียกใช้
n.Swap(ref a, ref b);
Console.WriteLine("หลัง Swap: a={0}, b={1}", a, b);
Console.ReadLine();
}
}
}ผลลัพธ์
ก่อน Swap: a=100, b=200 หลัง Swap: a=200, b=100
ค่า a, b สลับกันจริง เพราะทำงานบนตัวแปรเดียวกัน
คีย์เวิร์ดที่เกี่ยวข้อง: ref, out, in
| คีย์เวิร์ด | ทิศทาง | ต้อง Initialize ก่อนส่ง | ต้อง Assign ในเมธอด | คำอธิบาย |
|---|---|---|---|---|
| ref | Two-way (In/Out) | ใช่ | ไม่ | อ่าน/เขียนตัวแปรจริง |
| out | Out Only | ไม่ | ใช่ (บังคับ) | สำหรับ Return หลายค่า |
| in | In Only (Readonly) | ใช่ | ไม่ (Compile Error) | Pass by Reference แบบอ่านอย่างเดียว |
ตัวอย่าง out Parameter (Return หลายค่า)
public bool TryParseInt(string input, out int result)
{
return int.TryParse(input, out result);
}
// ใช้งาน
if (TryParseInt("123", out int value))
Console.WriteLine("Parsed: " + value); // 123ตัวอย่าง in Parameter (Readonly Reference)
// ส่ง Struct ใหญ่ๆ แบบไม่ Copy และไม่ให้แก้ไข
public void ProcessLargeStruct(in BigStruct data)
{
// data.X = 10; // Compile Error! Cannot assign to 'in' parameter
Console.WriteLine(data.X); // อ่านได้
}
// ใช้งาน
BigStruct s = new BigStruct { X = 42 };
ProcessLargeStruct(in s); // หรือ ProcessLargeStruct(s) ก็ได้ (in implicit)แผนภาพหน่วยความจำ (ref)
Main Stack Frame:
┌─────────┐
│ a: 100 │ ◄───┐
└─────────┘ │ Same Memory Location
▼
Swap Stack Frame:
┌─────────┐
│ x (ref) │ ─── Points to 'a'
├─────────┤
│ y (ref) │ ─── Points to 'b'
└─────────┘ข้อสังเกตสำคัญ
refต้อง Initialize ก่อนส่ง (Definite Assignment)outไม่ต้อง Initialize ก่อน แต่บังคับ Assign ในเมธอดทุก Pathinเพิ่มใน C# 7.2 - เหมาะสำหรับ Struct ใหญ่ (Performance) และบ่งชี้ Intent (Read-only)- Properties ไม่สามารถส่งเป็น
ref/outได้ (เพราะไม่ใช่ Variable) - ต้อง Copy ไป Variable ก่อน - Async Methods ไม่รองรับ
ref/outParameters - Iterator Methods (
yield return) ไม่รองรับref/out
เมื่อไหร่ควรใช้ ref/out/in
ref: Swap, 修改參數, 高性能 Struct 傳遞out: TryParse Pattern, 多返回值in: 大型 Struct 傳遞 (避免 Copy), 唯讀參數