Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C#

Cải tiến Out Parameter trong C# 7.0

Có thể khai báo out values inline như arguments của method nơi chúng được dùng.

Existing out parameters đã được cải tiến trong version này. Giờ có thể khai báo out variables trong argument list của method call, thay vì viết separate declaration statement.

Ưu điểm

  • Code dễ đọc hơn.
  • Không cần assign initial value.

Existing Syntax (Trước C# 7.0)

class Program { 
    public static void AddMultiplyValues(int a, int b, out int c, out int d) { 
        c = a + b; 
        d = a * b; 
    } 
    
    public static void Main() { 
        int c; 
        int d; 
        AddMultiplyValues(5, 10, out c, out d); 
        System.Console.WriteLine(c); 
        System.Console.WriteLine(d); 
        Console.ReadLine(); 
    } 
}

Output

15
50

New Syntax (C# 7.0+)

class Program { 
    public static void AddMultiplyValues(int a, int b, out int c, out int d) { 
        c = a + b; 
        d = a * b; 
    } 
    
    public static void Main() { 
        AddMultiplyValues(5, 10, out int c, out int d); 
        System.Console.WriteLine(c); 
        System.Console.WriteLine(d); 
        Console.ReadLine(); 
    } 
}

Output

15
50

Out Variables Chi Tiết

Scope của Out Variables

public void Demo() {
    // Out variable scope: trong block chứa method call
    GetValues(out int x, out int y);
    Console.WriteLine($"{x}, {y}"); // x, y accessible here
    
    if (TryParse(input, out int number)) {
        Console.WriteLine(number); // number accessible trong if block
    }
    // number KHÔNG accessible ở đây (nếu C# 7.0-7.2)
    // C# 7.3+: number accessible ở đây (scope mở rộng)
}

Var Type Inference

// Compiler infer type từ method signature
GetCoordinates(out var x, out var y); // x, y inferred as int

// Với generic methods
void GetValue(out T value) { ... }
GetValue(out var value); // T inferred from context or default

Discards với Out Parameters (C# 7.0+)

// Bỏ qua out parameter không cần
GetCoordinates(out int x, out _); // Chỉ cần x
GetCoordinates(out _, out _);     // Bỏ qua cả hai

// TryParse pattern phổ biến
if (int.TryParse(input, out _)) {
    // Chỉ check parse success, không cần value
}

Out vs Ref vs In

Keyword Direction Initialization Required Caller Must Initialize C# 7.0 Inline Declaration
out Out-only (write) Method PHẢI assign trước return Không (C# 7.0+) ✅ out int x
ref In-Out (read/write) Method có thể read/write Có (phải initialized) ✅ ref int x (C# 7.0+)
in In-only (read) Method KHÔNG được modify Có ❌ Không hỗ trợ inline

Ref Inline Declaration (C# 7.0+)

void Swap(ref int a, ref int b) {
    int temp = a; a = b; b = temp;
}

var x = 1; var y = 2;
Swap(ref x, ref y); // Traditional
Swap(ref int a = ref x, ref int b = ref y); // C# 7.0+ inline (rarely used)

TryParse Pattern - Best Practice

// Trước C# 7.0
int number;
bool success = int.TryParse(input, out number);
if (success) { ... }

// C# 7.0+ - Clean hơn
if (int.TryParse(input, out int number)) {
    Console.WriteLine($"Parsed: {number}");
}

// C# 7.0+ với discard
if (int.TryParse(input, out _)) {
    Console.WriteLine("Valid integer format");
}

// Pattern matching (C# 7.0+)
if (input is int number) { // Chỉ work với constant pattern, không TryParse
    // ...
}

// Custom TryParse pattern
public bool TryGetUser(int id, out User user) {
    user = _repository.GetById(id);
    return user != null;
}

// Usage
if (TryGetUser(123, out var user)) {
    Console.WriteLine(user.Name);
}

Async Out Parameters (Not Supported)

C# không support async out parameters. Workarounds:

// 1. Return tuple
public async Task<(bool Success, User User)> TryGetUserAsync(int id) {
    var user = await _repository.GetByIdAsync(id);
    return (user != null, user);
}

// 2. Custom result class
public class TryResult {
    public bool Success { get; }
    public T Value { get; }
    public Exception Error { get; }
    
    public static TryResult Success(T value) => new TryResult { Success = true, Value = value };
    public static TryResult Failure(Exception ex) => new TryResult { Success = false, Error = ex };
}

public async Task> TryGetUserAsync(int id) {
    try {
        var user = await _repository.GetByIdAsync(id);
        return user != null ? TryResult.Success(user) : TryResult.Failure(new KeyNotFoundException());
    } catch (Exception ex) {
        return TryResult.Failure(ex);
    }
}