Bài 9: Các từ khóa tham số đặc biệt trong Hàm (ref, out, in, params)
🎯 Mục tiêu bài học
-
Hiểu cơ chế truyền tham số mặc định theo Giá trị (Value) và Tham chiếu (Reference) trong C#.
-
Nắm vững cách sử dụng các từ khóa nâng cao:
ref,out,in, vàparams. -
Biết cách viết các hàm linh hoạt có thể nhận số lượng tham số tùy biến (variable arguments).
📖 Phần 1: Truyền tham số mặc định hoạt động thế nào?
Mặc định khi bạn truyền một biến vào hàm, C# sẽ tạo ra một bản copy của biến đó. Mọi thay đổi diễn ra bên trong hàm sẽ không làm ảnh hưởng đến biến gốc bên ngoài.
C#
static void UpdateScore(int score)
{
score = 10; // Thay đổi bên trong hàm
}
// Bên ngoài Main:
int myScore = 5;
UpdateScore(myScore);
Console.WriteLine(myScore); // Vẫn là 5! Vì hàm chỉ sửa trên bản copy.
Nhưng nếu bạn muốn hàm thay đổi trực tiếp giá trị của biến gốc, hoặc muốn hàm trả về nhiều kết quả cùng lúc, bạn cần nhờ đến các từ khóa đặc biệt.
📖 Phần 2: Các từ khóa tham số đặc biệt
1. ref (Tham chiếu 2 chiều)
-
Mục đích: Cho phép hàm thay đổi giá trị của biến gốc và biến đó bắt buộc phải được gán giá trị trước khi truyền vào hàm.
-
Ví dụ:
C#
static void AddBonus(ref int score) { score += 2; // Sửa trực tiếp biến gốc bên ngoài } // Cách dùng: int points = 8; AddBonus(ref points); // Phải có từ khóa ref ở cả khi gọi hàm Console.WriteLine(points); // Kết quả: 10
2. out (Đầu ra - Trả về nhiều kết quả)
-
Mục đích: Giống như
ref, nhưng biến truyền vào không cần khởi tạo giá trị trước. Hàm bắt buộc phải gán giá trị cho biếnouttrước khi kết thúc. Rất hữu ích khi bạn muốn hàm trả về nhiều hơn 1 kết quả (vd: hàmint.TryParsecủa C# dùngoutđể trả về số đã chuyển đổi). -
Ví dụ:
C#
static void Calculate(int a, int b, out int sum, out int product) { sum = a + b; // Bắt buộc phải gán giá trị trong hàm product = a * b; // Bắt buộc phải gán giá trị trong hàm } // Cách dùng: Calculate(3, 4, out int s, out int p); Console.WriteLine($"Tong: {s}, Tich: {p}"); // Tong: 7, Tich: 12
3. in (Chỉ đọc - Tối ưu hiệu suất)
-
Mục đích: Dành cho các cấu trúc dữ liệu lớn (như struct lớn hoặc object).
inbáo cho C# biết: "Hãy truyền tham chiếu để tiết kiệm bộ nhớ, nhưng cấm hàm này sửa đổi dữ liệu bên trong". -
Ví dụ:
C#
static void PrintData(in int largeNumber) { // largeNumber = 10; -> Lỗi biên dịch vì 'in' là Read-only Console.WriteLine(largeNumber); }
4. params (Nhận danh sách tham số vô định)
-
Mục đích: Cho phép bạn truyền một danh sách các giá trị rời rạc vào hàm, và hàm sẽ tự động gom chúng lại thành một mảng. Phải đặt
paramsở tham số cuối cùng trong khai báo hàm. -
Ví dụ:
C#
static int SumAll(params int[] numbers) { int total = 0; foreach (int n in numbers) { total += n; } return total; } // Cách dùng cực kỳ linh hoạt, truyền bao nhiêu số cũng được: int kq1 = SumAll(1, 2, 3); // Kết quả: 6 int kq2 = SumAll(5, 10, 15, 20, 25); // Kết quả: 75
💻 Phần 3: Thực hành
Viết một chương trình xử lý giỏ hàng, sử dụng out để trả về cả Tổng tiền và Tổng số lượng sản phẩm, đồng thời dùng params để tính tổng tiền thanh toán cho danh sách các mặt hàng linh hoạt:
C#
using System;
namespace Lesson9
{
class Program
{
static void Main(string[] args)
{
// Sử dụng hàm với params để tính tổng tiền nhanh các món hàng
double finalTotal = CalculateTotal(150000, 300000, 50000, 1200000);
Console.WriteLine($"Tong tien thanh toan: {finalTotal:N0} VND");
// Sử dụng hàm với out để bóc tách thông tin
AnalyzeCart(out int totalItems, out double averagePrice, 100000, 200000, 300000);
Console.WriteLine($"So luong mon hang: {totalItems}");
Console.WriteLine($"Gia trung binh moi mon: {averagePrice:N0} VND");
Console.ReadLine();
}
// 1. Hàm dùng params nhận danh sách giá tiền tùy ý
static double CalculateTotal(params double[] prices)
{
double sum = 0;
foreach (double price in prices)
{
sum += price;
}
return sum;
}
// 2. Hàm dùng out để trả về nhiều kết quả cùng lúc
static void AnalyzeCart(out int count, out double avg, params double[] prices)
{
count = prices.Length;
double total = 0;
foreach (double p in prices)
{
total += p;
}
avg = count > 0 ? total / count : 0;
}
}
}
📝 Tóm tắt bài học
-
Mặc định: Truyền tham số theo giá trị (tạo bản copy, không ảnh hưởng biến gốc).
-
ref: Tham chiếu 2 chiều, biến phải được khởi tạo trước. -
out: Biến đầu ra giúp hàm trả về nhiều kết quả, biến không cần khởi tạo trước nhưng hàm bắt buộc phải gán giá trị. -
in: Tham chiếu chỉ đọc (read-only) để tối ưu hiệu suất với dữ liệu lớn. -
params: Gom nhiều tham số rời rạc thành một mảng, giúp gọi hàm cực kỳ linh hoạt.
🛠 Bài tập thực hành
Yêu cầu: Viết hàm hoán đổi giá trị (Swap):
-
Viết một hàm có tên là
Swapnhận vào hai biến số nguyên (int a,int b) sao cho khi gọi hàm này ởMain, giá trị của 2 biến sẽ bị đổi chỗ cho nhau (Biếnx = 5,y = 10sau khi chạy hàmSwapsẽ thànhx = 10,y = 5). -
Gợi ý: Bắt buộc phải dùng từ khóa gì để hàm thay đổi được biến gốc bên ngoài?
All rights reserved