ภาพรวม
Pass by Value (การส่งค่า) เป็นกลไกเริ่มต้น (Default) ของ C# เมื่อส่งพารามิเตอร์เข้าเมธอด จะสร้าง ตำแหน่งหน่วยความจำใหม่ และ คัดลอกค่า จากตัวแปรจริง (Argument) ไปยังพารามิเตอร์ (Parameter) การเปลี่ยนแปลงพารามิเตอร์ภายในเมธอด ไม่ส่งผลต่อ ตัวแปรต้นฉบับ
ตัวอย่างโปรแกรม: Sw แบบ Pass by Value
using System;
namespace CalculatorApplication
{
class NumberManipulator
{
public void Swap(int x, int y)
{
int temp = x;
x = y;
y = temp;
Console.WriteLine("ในเมธอด Swap: x={0}, y={1}", x, y);
}
static void Main(string[] args)
{
NumberManipulator n = new NumberManipulator();
int a = 100;
int b = 200;
Console.WriteLine("ก่อน Swap: a={0}, b={1}", a, b);
n.Swap(a, b); // ส่งค่า (Copy)
Console.WriteLine("หลัง Swap: a={0}, b={1}", a, b);
Console.ReadLine();
}
}
}ผลลัพธ์
ก่อน Swap: a=100, b=200 ในเมธอด Swap: x=200, y=100 หลัง Swap: a=100, b=200
ค่า a, b ไม่เปลี่ยน เพราะส่งเป็น Copy
แผนภาพหน่วยความจำ
Main Stack Frame: Swap Stack Frame: ┌─────────┐ ┌─────────┐ │ a: 100 │ ───Copy───▶ │ x: 100 │ ──Swap──▶ │ x: 200 │ ├─────────┤ ├─────────┤ ├─────────┤ │ b: 200 │ ───Copy───▶ │ y: 200 │ ──Swap──▶ │ y: 100 │ └─────────┘ └─────────┘ └─────────┘ หลัง Swap กลับมา: a=100, b=200 (ไม่เปลี่ยน)
พฤติกับกับ Reference Types (Class, Array, String)
แม้จะเป็น Pass by Value แต่ถ้าพารามิเตอร์เป็น Reference Type จะ Copy Reference (Address) ไป → สามารถแก้ไข เนื้อหา Object ได้ แต่ ไม่สามารถเปลี่ยน Reference ของตัวแปรต้นฉบับได้
void Modify(StringBuilder sb)
{
sb.Append(" World"); // แก้ไขเนื้อหา Object ได้ ✓
sb = new StringBuilder("New"); // เปลี่ยน Reference ตัวแปร Parameter เท่านั้น ✗
}
StringBuilder s = new StringBuilder("Hello");
Modify(s);
Console.WriteLine(s); // "Hello World" - เนื้อหาเปลี่ยน!Pass by Value vs Pass by Reference
| คุณสมบัติ | Pass by Value (Default) | Pass by Reference (ref/out) |
|---|---|---|
| คีย์เวิร์ด | (ไม่มี) | ref / out / in |
| Value Types (int, struct) | Copy ค่า | Reference ตัวแปรจริง |
| Reference Types (class) | Copy Reference | Reference ตัวแปรจริง |
| แก้ไขค่า Parameter | ไม่ส่งผลต่อ Argument | ส่งผลต่อ Argument |
| แก้ไข Object เนื้อหา | ได้ (ถ้าเป็น Ref Type) | ได้ |
ข้อสังเกตสำคัญ
- ค่าเริ่มต้นของ C# คือ Pass by Value เสมอ
- Struct ใหญ่ๆ การส่งแบบ Value อาจช้า (Copy มาก) → ใช้
in(readonly reference) หรือref - String เป็น Immutable - Pass by Value ปลอดภัย เพราะแก้ไขไม่ได้
- การออกแบบ API: ควรใช้ Pass by Value สำหรับ Input ที่ไม่ต้องแก้ไข ใช้
ref/outเมื่อต้องการให้เมธอดเปลี่ยนค่าตัวแปรจริง