Local Functions เป็น Private Methods ของ Type ที่ Nested อยู่ใน Member อื่น สามารถเรียกได้เฉพาะจาก Containing Member เท่านั้น
Local Functions สามารถ Declare และ Call ได้จาก:
- Methods (รวม Iterator Methods และ Async Methods)
- Constructors
- Property Accessors
- Event Accessors
- Anonymous Methods
- Lambda Expressions
- Finalizers
- Local Functions อื่นๆ (Nested)
ตัวอย่างพื้นฐาน
class Program {
public static void Main() {
// Local Function Declaration
void AddTwoNumbers(int a, int b) {
Console.WriteLine(a + b);
}
// Call Local Function
AddTwoNumbers(1, 2);
Console.ReadLine();
}
}
Output
3
ตัวอย่างกับ Out Parameter
class Program {
public static void Main() {
void AddTwoNumbers(int a, int b, out int c) {
c = a + b;
}
AddTwoNumbers(1, 2, out int c);
Console.WriteLine(c);
Console.ReadLine();
}
}
Output
3
Use Cases จริงของ Local Functions
1. Iterator Methods (Lazy Evaluation)
public IEnumerable GetEvenNumbers(int start, int count) {
// Validation รันทันที (Eager)
if (count < 0) throw new ArgumentException("Count must be positive");
// Iterator Logic เป็น Local Function (Lazy)
IEnumerable Iterator() {
for (int i = 0; i < count; i++) {
yield return start + i * 2;
}
}
return Iterator();
}
// Usage: Validation รันทันที, Iteration ทีหลัง
var evens = GetEvenNumbers(2, 5); // No iteration yet
foreach (var n in evens) { // เริ่ม Iterate ตรงนี้
Console.WriteLine(n); // 2, 4, 6, 8, 10
}
2. Async Methods (Eager Validation + Lazy Execution)
public async Task ProcessAsync(string input) {
// Validate ทันที
if (string.IsNullOrEmpty(input))
throw new ArgumentException("Input required");
// Async Local Function
async Task ProcessCoreAsync() {
var data = await FetchDataAsync(input);
return Transform(data);
}
return await ProcessCoreAsync();
}
3. Recursive Algorithms
public int Factorial(int n) {
if (n < 0) throw new ArgumentException();
int FactorialImpl(int x) {
return x <= 1 ? 1 : x * FactorialImpl(x - 1);
}
return FactorialImpl(n);
}
4. Encapsulation ของ Helper Logic
public class OrderProcessor {
public OrderResult Process(Order order) {
decimal CalculateTax(Order o) => o.SubTotal * 0.07m;
decimal CalculateDiscount(Order o) => o.Customer.IsVip ? o.SubTotal * 0.1m : 0;
var tax = CalculateTax(order);
var discount = CalculateDiscount(order);
var total = order.SubTotal + tax - discount;
return new OrderResult { Total = total, Tax = tax, Discount = discount };
}
}
5. 在 Constructors
public class Config {
public string ConnectionString { get; }
public int Timeout { get; }
public Config(IConfiguration config) {
void ValidateAndSet(string key, Action setter, string defaultValue = null) {
var value = config[key] ?? defaultValue;
if (string.IsNullOrEmpty(value))
throw new InvalidOperationException($"Missing config: {key}");
setter(value);
}
ValidateAndSet("ConnectionString", v => ConnectionString = v);
ValidateAndSet("Timeout", v => Timeout = int.Parse(v), "30");
}
}
Local Functions vs Lambda Expressions
| Feature | Local Function | Lambda Expression |
|---|---|---|
| Syntax | void Name() { } | () => { } |
| Delegate Allocation | ไม่มี (Direct Call) | มี (Delegate Object) |
| Recursion | Natural (เรียกชื่อ Function) | ต้องใช้ Delegate Variable |
| Ref/Out Params | รองรับ | ไม่รองรับ |
| Yield Return | รองรับ (Iterator) | ไม่รองรับ |
| Async | รองรับ | รองรับ |
| Attributes | รองรับ | ไม่รองรับ |
ข้อจำกัด
- ไม่สามารถเป็น
staticได้ (ยกเว้นใน Static Method) - ไม่สามารถมี Access Modifiers (public, private, etc.)
- ไม่สามารถ Overload ได้ (ใน Scope เดียวกัน)
- ไม่สามารถเข้าถึงจากภายนอก Containing Member