Reference Return Value อนุญาตให้ Method คืนค่า Reference ไปยัง Variable แทนที่จะคืนค่า Value
Caller สามารถเลือกได้ว่าจะจัดการ Returned Variable ว่าเป็น Pass by Value หรือ Pass by Reference
Caller สามารถสร้าง Variable ใหม่ที่เป็น Reference ของ Returned Value เรียกว่า Ref Local
ปัญหา: Pass by Value (ปกติ)
class Program {
public static void Main() {
var colors = new[] { "blue", "green", "yellow", "orange", "pink" };
string color = colors[3]; // Copy Value
color = "Magenta"; // แก้ไข Copy เท่านั้น
Console.WriteLine(string.Join(" ", colors));
// Output: blue green yellow orange pink (ไม่เปลี่ยน!)
Console.ReadLine();
}
}
แก้ด้วย Ref Locals
public static void Main() {
var colors = new[] { "blue", "green", "yellow", "orange", "pink" };
// ref local - อ้างอิงตรง Element ใน Array
ref string color = ref colors[3];
color = "Magenta"; // แก้ไข Element จริงใน Array
Console.WriteLine(string.Join(" ", colors));
// Output: blue green yellow Magenta pink
Console.ReadLine();
}
Ref Returns
Method คืนค่า Reference แทน Value
โดยไม่มี Ref Return (Pass by Value)
class Program {
public static void Main() {
var colors = new[] { "blue", "green", "yellow", "orange", "pink" };
string color = GetColor(colors, 3); // Return Value (Copy)
color = "Magenta";
Console.WriteLine(string.Join(" ", colors));
// Output: blue green yellow orange pink
Console.ReadLine();
}
public static string GetColor(string[] col, int index) {
return col[index]; // Return Value
}
}
ใช้ Ref Return
class Program {
public static void Main() {
var colors = new[] { "blue", "green", "yellow", "orange", "pink" };
// รับ Reference จาก Method
ref string color = ref GetColor(colors, 3);
color = "Magenta";
Console.WriteLine(string.Join(" ", colors));
// Output: blue green yellow Magenta pink
Console.ReadLine();
}
// Ref Return: คืน Reference ไปยัง Array Element
public static ref string GetColor(string[] col, int index) {
return ref col[index];
}
}
กฎของ Ref Returns
- Return Type ต้องเป็น
ref T - Return Statement ต้องเป็น
return ref variable; - สามารถ Return Reference ได้เฉพาะ:
- Fields/Array Elements ของ Object ที่มีอยู่แล้ว
- Ref Parameters ที่รับเข้ามา
- Ref Locals ใน Method เดียวกัน
- ไม่สามารถ Return Reference ของ Local Variable (จะ Out of Scope)
ตัวอย่างขั้นสูง: หา Element และแก้ไขในที่เดียว
public class Matrix {
private double[,] _data;
public Matrix(int rows, int cols) {
_data = new double[rows, cols];
}
// Ref Return: เข้าถึง Element โดยตรง
public ref double this[int row, int col] {
get => ref _data[row, col];
}
// หา Max Element และ Return Reference
public ref double FindMax() {
int maxRow = 0, maxCol = 0;
for (int r = 0; r < _data.GetLength(0); r++) {
for (int c = 0; c < _data.GetLength(1); c++) {
if (_data[r, c] > _data[maxRow, maxCol]) {
maxRow = r; maxCol = c;
}
}
}
return ref _data[maxRow, maxCol];
}
}
// Usage
var matrix = new Matrix(3, 3);
// ... fill data ...
ref double max = ref matrix.FindMax();
max = 0; // Reset Max to 0 โดยตรงใน Array
Ref Structs (C# 7.2+) - Stack-only Types
// Ref Struct ต้องอยู่บน Stack เท่านั้น (ไม่มี Heap Allocation)
public ref struct SpanWrapper {
private Span _span;
public SpanWrapper(Span span) => _span = span;
public ref int this[int index] => ref _span[index];
}
// Usage - ต้องใช้กับ Stack-allocated Memory
Span stackSpan = stackalloc int[100];
var wrapper = new SpanWrapper(stackSpan);
wrapper[0] = 42;
สรุปเมื่อไหร่ใช้ Ref Returns/Locals
- Performance-critical Code ที่ต้องหลีกเลี่ยง Copy Large Structs
- Direct Mutation ของ Elements ใน Collections/Arrays
- Search/Find Methods ที่ต้องการแก้ไข Element ที่เจอทันที
- High-frequency Trading, Game Engines, Numerical Computing
- ไม่ควรใช้ ใน General Business Logic (Complexity เพิ่มขึ้น, Safety ลดลง)