Contents
Khái niệm dễ hiểu về Tham chiếu và Tham trị
Để hiểu rõ tham trị (pass by value) và tham chiếu (pass by reference), bạn có thể tưởng tượng hai cách này giống như cách bạn làm việc với một bản sao của tài liệu hoặc với tài liệu gốc.
1. Tham trị (Pass by Value)
- Khi bạn truyền tham trị, một bản sao của giá trị được truyền vào phương thức.
- Thay đổi trên bản sao này không ảnh hưởng đến giá trị gốc của biến bên ngoài.
Ví dụ dễ hiểu: Bạn đưa một bản sao của tài liệu cho người khác sửa đổi. Họ có thể chỉnh sửa trên bản sao, nhưng tài liệu gốc của bạn vẫn không bị ảnh hưởng.
Trong lập trình:
void ChangeValue(int number)
{
number = 10; // Thay đổi trên bản sao
}
int x = 5;
ChangeValue(x);
Console.WriteLine(x); // Output: 5 (giá trị gốc không thay đổi)
Giải thích:
- Biến
x
(giá trị gốc) được truyền vào phương thứcChangeValue
. - Một bản sao của
x
được tạo ra trong phương thức. - Thay đổi
number
không ảnh hưởng đếnx
vìnumber
chỉ là bản sao.
2. Tham chiếu (Pass by Reference)
- Khi bạn truyền tham chiếu, bạn không truyền giá trị, mà truyền một địa chỉ tham chiếu đến biến gốc.
- Thay đổi trên biến trong phương thức sẽ ảnh hưởng trực tiếp đến giá trị gốc của biến bên ngoài.
Ví dụ dễ hiểu: Bạn đưa tài liệu gốc cho người khác chỉnh sửa. Họ thay đổi trên tài liệu gốc, nên bạn cũng sẽ thấy những thay đổi đó.
Trong lập trình:
void ChangeValue(ref int number)
{
number = 10; // Thay đổi trên biến gốc
}
int x = 5;
ChangeValue(ref x);
Console.WriteLine(x); // Output: 10 (giá trị gốc bị thay đổi)
Giải thích:
- Biến
x
được truyền vào phương thứcChangeValue
bằng tham chiếu (ref
). - Mọi thay đổi trên
number
trong phương thức sẽ ảnh hưởng trực tiếp đếnx
.
Sự khác biệt giữa Tham trị và Tham chiếu
Đặc điểm | Tham trị (Pass by Value) | Tham chiếu (Pass by Reference) |
---|---|---|
Cách truyền | Truyền một bản sao của giá trị | Truyền địa chỉ tham chiếu |
Tác động đến biến gốc | Không ảnh hưởng | Ảnh hưởng trực tiếp |
Dùng từ khóa | Không cần từ khóa | Dùng từ khóa ref hoặc out |
Ví dụ thực tế | Sửa đổi trên bản sao của tài liệu | Sửa đổi trên tài liệu gốc |
Kiểu Giá trị (Value Type)
Kiểu giá trị lưu trữ trực tiếp dữ liệu trong vùng nhớ của biến. Khi bạn gán một biến kiểu giá trị cho biến khác, một bản sao của dữ liệu được tạo ra, và hai biến hoạt động độc lập với nhau. Các kiểu giá trị bao gồm:
- Các kiểu số nguyên:
int
,byte
,long
, v.v. - Các kiểu số thực:
float
,double
,decimal
- Kiểu
bool
: lưu trữ giá trịtrue
hoặcfalse
- Kiểu
char
: lưu trữ một ký tự Unicode - Kiểu cấu trúc (
struct
): do người dùng định nghĩa - Kiểu liệt kê (
enum
): tập hợp các hằng số
Ví dụ:
int a = 5;
int b = a; // Sao chép giá trị của a vào b
b = 10;
Console.WriteLine(a); // Output: 5
Console.WriteLine(b); // Output: 10
Trong ví dụ này, a
và b
là hai biến độc lập; thay đổi b
không ảnh hưởng đến a
.
Kiểu Tham chiếu (Reference Type)
Kiểu tham chiếu lưu trữ địa chỉ của dữ liệu trong bộ nhớ, thay vì lưu trữ trực tiếp dữ liệu. Khi bạn gán một biến kiểu tham chiếu cho biến khác, cả hai biến sẽ tham chiếu đến cùng một đối tượng trong bộ nhớ. Do đó, thay đổi thông qua một biến sẽ ảnh hưởng đến biến kia. Các kiểu tham chiếu bao gồm:
- Lớp (
class
): do người dùng định nghĩa - Giao diện (
interface
) - Mảng
- Ủy quyền (
delegate
) - Kiểu
object
: lớp cơ sở cho tất cả các kiểu trong C# - Kiểu
string
: chuỗi ký tự
Ví dụ:
class Person
{
public string Name { get; set; }
}
Person person1 = new Person { Name = "Alice" };
Person person2 = person1; // Cả hai biến tham chiếu đến cùng một đối tượng
person2.Name = "Bob";
Console.WriteLine(person1.Name); // Output: Bob
Truyền Tham số: Tham trị và Tham chiếu
Khi gọi phương thức, các tham số có thể được truyền theo hai cách:
- Tham trị (pass by value): Giá trị của biến được sao chép và truyền vào phương thức. Thay đổi trong phương thức không ảnh hưởng đến biến gốc.
- Tham chiếu (pass by reference): Tham chiếu đến biến được truyền vào phương thức. Thay đổi trong phương thức sẽ ảnh hưởng trực tiếp đến biến gốc.
Sử dụng từ khóa ref
và out
:
ref
: Dùng để truyền tham chiếu đến biến đã được khởi tạo.out
: Dùng để truyền tham chiếu đến biến chưa cần khởi tạo; phương thức bắt buộc phải gán giá trị trước khi kết thúc.
Ví dụ với ref
:
void Square(ref int number)
{
number = number * number;
}
int x = 5;
Square(ref x);
Console.WriteLine(x); // Output: 25
Trong ví dụ này, biến x
được truyền theo tham chiếu vào phương thức Square
. Do đó, thay đổi trong phương thức ảnh hưởng trực tiếp đến x
.
Ví dụ với out
:
void Initialize(out int number)
{
number = 10;
}
int y;
Initialize(out y);
Console.WriteLine(y); // Output: 10
Ở đây, biến y
chưa được khởi tạo nhưng có thể được truyền vào phương thức Initialize
bằng từ khóa out
. Phương thức này gán giá trị cho y
trước khi kết thúc.