Kiểu giá trị trong C#
Kiểu giá trị và kiểu tham chiếu là hai nhóm chính phân loại kiểu dữ liệu của C#. Một biến kiểu giá trị thì biến đó sẽ lưu giá trị của đối tượng lưu trữ, khác với kiểu tham chiếu biến chứa địa chỉ trỏ đến nơi lưu đối tượng thực. Kiểu giá trị mặc định trong các phép toán gán, truyền tham số phương thức, kể cả trả về từ hàm - thì giá trị được sao chép.
public static void valuetypeExample() { // biến a, kiểu int là kiểu giá trị, nó lưu giá trị 100 int a = 100; // kiểu giá trị khi gán, giá trị được copy int b = a; Console.WriteLine($"a = {a}, b = {b}"); // b gán giá trị mới, a không thay đổi - vì chúng không cùng tham // chiếu đến 1 đối tượng chung, mà mỗi biến lưu một giá trị b = 200; Console.WriteLine($"a = {a}, b = {b}"); // a = 100, b = 100 // a = 100, b = 200 }
Khi biến thuộc các kiểu sau, mặc định nó ứng xử là kiểu giá trị:
- Các kiểu số nguyên như
int
,byte
,long
... - Các kiểu số thực như
float
,double
,decimal
- Kiểu
bool
, kiểuchar
- Kiểu cấu trúc
struct
- Kiểu liệt kê
enum
- Kiểu
Tuple
Kiểu tham chiếu trong C#
Các biến kiểu tham chiếu nó chứa tham chiếu (địa chỉ nhớ) trỏ đến dữ liệu (là đối tượng), với kiểu tham chiếu hai biến, hay nhiều biến có tên khác nhau có thể cùng trỏ đến cùng mội đối tượng, khi đó dùng biến biến nào truy cập, tác động vào đối tượng đều mang lại kết quả như nhau.
Như vậy khi dùng kiểu tham chiếu, truyền dữ liệu trong hàm hay các phép gán thì không phải là copy đối tượng hay giá trí mà chỉ là truyền tham chiếu (địa chỉ nhớ).
Những biển có kiểu sau thì nó là kiểu tham chiếu:
- Biến kiểu lớp (
class
), các lớp thư viện hoặc lớp do bạn định nghĩa - Biến kiểu
delegate
- Biến kiểu
interface
, các giao diện từ thư viện hoặc tự định nghĩa - Biến kiểu
dynamic
- Biến kiểu
object
- Biến kiểu
string
Ví dụ có lớp Student
class Stutent { public string Name; public Stutent(string name) { this.Name = name; } }
Vì là lớp nên biến kiểu Student
trên sẽ là kiểu tham chiếu, ví dụ:
Stutent a = new Stutent("Nguyễn Văn A"); Console.WriteLine(a.Name); // Nguyễn Văn A Stutent b; // Khi gán, tham chiếu không sao chép giá trị mà tham chiếu địa chỉ // nên có thể có a là b, b là a, b thay đổi nghĩa là a thay đổi b = a; b.Name = "Nguyễn Văn B"; Console.WriteLine(a.Name); // Nguyễn Văn B
Điều tương tự khi dùng làm tham số của phương thức, hàm. Nó tham chiếu chứ không copy giá trị
Khai báo một phương thức
// Tham số kiểu lớp, nên là tham chiếu static void UpperName(Stutent stutent) { stutent.Name = stutent.Name.ToUpper(); }
Stutent stutent1 = new Stutent("Xuan Thu Lab"); UpperName(stutent1); // Phương thức biến đổi tham số student, có nghĩa là // biến đổi biến student1 Console.WriteLine(stutent1.Name); // XUAN THU LAB
Truyền tham số kiểu giá trị với dạng tham chiếu trong C#
Có hai hình thức truyền tham số cho phương thức khi nó được gọi là tham trị và tham chiếu
- tham trị là cách thức mặc định khi tham số đó là kiểu giá trị. Có nghĩa là gán tham số bằng một biến, thì giá trị của biến được copy và sử dụng trong phương thức như biến cục bộ, còn bản thân biến bên ngoài không hề ảnh hưởng.
- tham chiếu là cách thức mặc định khi tham số đó là kiểu tham chiếu, thì bản thân biến ở tham số sẽ được hàm sử dụng trực tiếp (tham chiếu) chứ không tạo ra một biến cục bộ trong hàm, nên nó có tác động trực tiếp đến biến này bên ngoài.
Trong phần này mở rộng thêm, nếu muốn biến kiểu giá trị nhưng được truyền vào phương
thức dạng tham chiếu (giống cách thức biến tham chiếu) thì khai báo tham số ở
phương thức, cũng như khi gọi cần cho thêm từ khóa ref
Tham số là các đối tượng lớp, mặc định là tham chiếu.
Khai báo ref
ở tham số phương thức, bắt buộc khi gọi phải sử dụng
biến làm tham số chứ không được dùng giá trị.
Ví dụ tham chiếu với biến kiểu giá trị:
Sửa lại phương thức trên như sau
public static void ThamSoThamChieu(ref int x) { x = x * x; Console.WriteLine(x); }
Khi sử dụng:
int a = 2; ThamSoThamChieu(ref a); Console.WriteLine(a); // In ra // 4 // 4
Ta thấy a
sử dụng làm tham số cho phương thức, tham số x
tham chiếu đến a
, và khi trong hàm thay đổi x, nghĩa là thay đổi a
bên ngoài. (đều in ra 4)
Ngoài ra nếu gọi ThamChieuThamTri(5);
thì sẽ lỗi, vì tham chiếu yêu cầu đối số này phải là biến.
Tham chiếu với out
Ngoài dùng từ khóa ref
trong khai báo tham chiếu, bạn cũng có thể thay thế nó bằng
từ khóa out
, điểm khác biệt duy nhất là nếu dùng từ khóa out
thì tham số không
cần khởi tạo khi truyền cho phương thức, còn dùng ref
thì biến làm tham số phải khởi tạo.
public static void OutExample(out int x) { x = 100; }
Khi sử dụng:
int a; // biến a chưa khởi tạo OutExample(out a); // Giờ a = 100;
Source code: CS007A-REF-VALUE (Git), hoặc tải ex007a