CodeGym /Các khóa học /C# SELF /Hàm cục bộ

Hàm cục bộ

C# SELF
Mức độ, Bài học
Có sẵn

1. Giới thiệu

Bất kỳ coder nào cũng biết: function (hay method) thực chất là "con ngựa thồ" của mọi ứng dụng. Chúng giúp mình tổ chức code, tái sử dụng logic và không bị chết chìm trong biển copy-paste vô tận. Đến giờ, tất cả function bạn từng dùng đều là "hàng xóm" trong thân class hoặc struct.

Nhưng thử tưởng tượng bạn có một function to đùng với một đoạn logic nhỏ, muốn tách nó ra cho gọn mà không muốn lộ cho cả project. Ví dụ, một phép tính phụ trợ trong method mà chỗ khác không cần dùng.

Lúc này, hàm cục bộ sẽ cứu bạn.

Hàm cục bộ là function được khai báo bên trong một function khác (method, constructor, property hoặc thậm chí một hàm cục bộ khác). Và hàm cục bộ này chỉ thấy được bởi "cha mẹ" của nó, ngoài ra thì không ai biết.

Cú pháp hàm cục bộ


void MainMethod()
{
    Console.WriteLine("Bắt đầu chạy main method.");            // Начало работы основного метода.
    int result = InnerSum(5, 7);                              // Вызов локальной функции InnerSum (внутренняя сумма)
    Console.WriteLine($"Kết quả hàm cục bộ: {result}");    // Результат локальной функции: {result}

    // Hàm cục bộ khai báo ngay trong MainMethod
    
  
int InnerSum(int a, int b) // Hàm cục bộ cộng hai số { return a + b; // Trả về tổng a và b }
}

Ở ví dụ này, function InnerSum được khai báo ngay bên trong method MainMethod. Nó không thể truy cập từ ngoài main method — hoàn toàn không thể! Kiểu như một chỉ dẫn bí mật chỉ chia sẻ riêng tư thôi.

2. Cách khai báo và dùng hàm cục bộ ở đâu

Quy tắc cơ bản

  • Hàm cục bộ có thể khai báo trong: method, constructor, property, operator hoặc thậm chí một hàm cục bộ khác!
  • Hàm cục bộ chỉ thấy được trong phạm vi (scope) của nó.
  • Bạn có thể gọi hàm cục bộ trước hoặc sau khi khai báo trong function cha (C# sẽ phân tích trước).

Ví dụ: tính điểm trung bình


// Hàm chính để in điểm trung bình
void PrintAverageScore(int[] scores)
{
    if (scores.Length == 0)
    {
        Console.WriteLine("Không có điểm để tính."); // No scores to calculate.
        return;
    }

    double average = CalculateAverage(scores);
    Console.WriteLine($"Điểm trung bình: {average:0.00}"); // Average score

    // Hàm cục bộ để tính trung bình
    
  
double CalculateAverage(int[] arr) { int sum = 0; foreach (var score in arr) sum += score; return (double)sum / arr.Length; // Trả về trung bình }
} // Gọi function: int[] myScores = { 5, 4, 3, 4, 5 }; PrintAverageScore(myScores); // Sẽ in: Điểm trung bình: 4.20

Thấy tiện không? Không ai ngoài PrintAverageScore có thể dùng logic bên trong — hàm cục bộ CalculateAverage. Cách này giúp code gọn gàng và không làm bẩn global namespace với các method phụ trợ.

3. Hàm cục bộ và phạm vi (scope)

Điểm hay nhất của hàm cục bộ là phạm vi của nó chỉ nằm trong method "cha". Như vậy sẽ tránh làm "bẩn" class với các method nhỏ chỉ dùng một chỗ.


+-----------------+
|   Метод класса  |
|    void Foo()   |
|                 |
|   +-----------+ |
|   |  Hàm cục  | |
|   |   bộ      | |
|   +-----------+ |
+-----------------+
Hàm cục bộ chỉ tồn tại bên trong method nơi nó được khai báo

Hàm cục bộ tồn tại chỉ trong method nơi nó được khai báo. Nếu bạn cố gọi nó từ ngoài sẽ giống như gọi vào đường dây bí mật mà bạn không có số.

Nếu bạn lỡ gọi hàm cục bộ ngoài method cha, sẽ bị lỗi biên dịch: Tên '...' không tồn tại trong ngữ cảnh hiện tại.

Hàm cục bộ có thể truy cập biến của cha

Hàm cục bộ có thể truy cập tất cả biến của method cha — đó là siêu năng lực của nó!


void ShowStudent(string name, int age)
{
    string message = BuildMessage();
    Console.WriteLine(message);

    // Hàm cục bộ dùng biến "name" và "age"
    
  
string BuildMessage() { return $"Tên: { name}, Tuổi: { age}"; }
}

Cách này giúp code ngắn hơn và đỡ "ồn ào". Không cần truyền cả đống tham số vào mỗi method — hàm cục bộ "nhìn thấy" mọi thứ trong cha nó.

4. Hàm cục bộ trong vòng lặp và điều kiện

Bạn có thể khai báo hàm cục bộ ở bất kỳ mức lồng nào — kể cả trong vòng lặp hoặc nhánh điều kiện:


void ProcessNumbers(int[] numbers)
{
    foreach (int number in numbers)
    {
        if (number % 2 == 0)
        {
            Console.WriteLine($"{number} — số chẵn");
            PrintEvenMessage();
        }
        else
        {
            Console.WriteLine($"{number} — số lẻ");
        }

        
  
void PrintEvenMessage() { Console.WriteLine("Đây là số chẵn, chúc mừng!"); }
} }

Tuy nhiên, cách này có thể làm code khó đọc nếu có quá nhiều hàm cục bộ hoặc chúng quá dài. Đừng lạm dụng, nhưng biết là có thể làm vậy cũng hay.

Hàm cục bộ vs method private thông thường

Tiêu chí Hàm cục bộ Method private của class
Phạm vi Chỉ function cha Cả class
Truy cập biến cha Có Không (chỉ qua tham số)
Dễ đọc code Cao Trung bình
Khả năng tái sử dụng Thấp Cao
Dễ test Khó test Dễ test

5. Lỗi phổ biến và lưu ý khi dùng

Lỗi #1: gõ sai hoặc quên khai báo hàm cục bộ.
Nếu bạn gọi hàm cục bộ với tên sai hoặc quên khai báo, compiler sẽ báo lỗi CS0103 hoặc CS0128, và code sẽ không build được.

Lỗi #2: thay đổi biến bị capture (closure).
Khi hàm cục bộ thay đổi giá trị biến từ method ngoài, bạn có thể nhận kết quả không như mong đợi — biến bị capture có thể là bản sao hoặc tham chiếu, thay đổi nó sẽ ảnh hưởng logic.

Lỗi #3: bỏ qua gợi ý IDE về chuyển method private thành hàm cục bộ.
Nếu bạn để lại các method private không cần thiết trong class, dù IDE (ví dụ Rider) gợi ý chuyển thành hàm cục bộ, code sẽ nhanh chóng "rác" và khó đọc hơn.

Lỗi #4: lồng quá nhiều hàm cục bộ.
Quá nhiều mức lồng function sẽ làm code khó hiểu và khó debug. Ngắn gọn là chìa khóa để bảo trì dễ dàng.

2
Nhiệm vụ
C# SELF, mức độ, bài học
Đã khóa
Sử dụng hàm cục bộ để tính tổng hai số
Sử dụng hàm cục bộ để tính tổng hai số
2
Nhiệm vụ
C# SELF, mức độ, bài học
Đã khóa
Hàm cục bộ để kiểm tra số chẵn lẻ
Hàm cục bộ để kiểm tra số chẵn lẻ
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION