C# Cơ bản .NET Core §1 Cài đặt, chương trình C# đầu tiên §2 Biến, kiểu dữ liệu và nhập/xuất §3 Toán tử số học và gán §4 So sánh, logic và lệnh if, switch §5 Vòng lặp for, while §6 Phương thức - Method §7 Phương thức - Delegate §8 Lớp - Class §9 Namespace §10 Partial, Nested §11 Kiểu giá trị, tham chiếu §12 Kiểu vô danh và dynamic §13 Biểu thức lambda §14 Event §15 Hàm hủy - Quá tải toán tử - thành viên tĩnh - indexer §16 null và nullable §17 Mảng §18 Chuỗi ký tự §19 Tính kế thừa §20 Phương thức khởi tạo §21 Tính đa hình - abstract - interface §22 Struct và Enum §23 Ngoại lệ Exeption §24 IDisposable - using §25 File cơ bản §26 FileStream §27 Generic §28 Collection - List §29 SortedList §30 Queue / Stack §31 Linkedlist §32 Dictionary - HashSet §33 Phương thức mở rộng §34 ObservableCollection §35 LINQ §36 (Multithreading) async - bất đồng bộ §37 Type §38 Attribute Annotation §39 DI Dependency Injection §40 (Multithreading) Parallel §41 Thư viện lớp §42 (Networking) HttpClient §43 (Networking) HttpMessageHandler §44 (Networking) HttpListener §45 (Networking) Tcp TcpListenerr/TcpClient §46 (ADO.NET) SqlConnection §47 (ADO.NET) SqlCommand §48 (EF Core) Tổng quan §49 (EF Core) Tạo Model §50 (EF Core) Fluent API §51 (EF Core) Query §52 (EF Core) Scaffold §53 (EF Core) Migration §54 (ASP.NET CORE) Hello World! §55 (ASP.NET CORE) Middleware §56 (ASP.NET CORE) Map - Request - Response §57 (ASP.NET CORE) IServiceCollection - MapWhen §58 (ASP.NET CORE) Session - ISession §59 (ASP.NET CORE) Configuration §60 (ASP.NET CORE) Gửi Mail §61 (ASP.NET CORE) SASS/SCSS §62 (ASP.NET CORE) LibMan §63 (ASP.NET RAZOR) Khởi tạo và Route §64 (ASP.NET RAZOR) Cú pháp Razor §65 (ASP.NET RAZOR) Layout trong ASP.NET Core §66 (ASP.NET RAZOR) Partial §67 (ASP.NET RAZOR) ViewComponent §68 (ASP.NET RAZOR) TagHelper §69 (ASP.NET RAZOR) PageModel §70 (ASP.NET RAZOR) Model Binding §71 (ASP.NET RAZOR) HTML Form, Validation §72 (ASP.NET RAZOR) Upload File §73 (ASP.NET RAZOR) HtmlHelper §74 (ASP.NET RAZOR) Entity Framework §75 (ASP.NET RAZOR) Paging §76 (ASP.NET RAZOR) Identity (1) - Register, Login, Logout §77 (ASP.NET RAZOR) Identity (2) Lockout, Reset Password §78 (ASP.NET RAZOR) Identity (3) Google Login §79 (ASP.NET RAZOR) Identity (4) Facebook Login §80 (ASP.NET RAZOR) Identity (5) profile, password, email ... §81 (ASP.NET RAZOR) Identity (6) Role §82 (ASP.NET RAZOR) Identity (7) Role-based Authorization §83 (ASP.NET RAZOR) Identity (8) RoleClaim §84 (ASP.NET RAZOR) Identity (9) Authorization Handler §85 (ASP.NET RAZOR) IAuthorizationService §86 (ASP.NET MVC) Controller - View §87 (ASP.NET MVC) Route §88 (ASP.NET MVC) EF, Identity §89 (ASP.NET MVC) Binding, Validation §90 (ASP.NET MVC) Xây dựng Website(1) §91 (ASP.NET MVC) Xây dựng Website(2) §92 (ASP.NET MVC) Xây dựng Website(3) §93 (ASP.NET MVC) Xây dựng Website(4) §94 (ASP.NET MVC) Giỏ hàng - Cart (5) §95 (ASP.NET MVC) elFinder (5) §96 (ASP.NET MVC) SB Admin (6) §97 (ASP.NET MVC) Kestrel, publish
Partial, Nested (Bài trước)

Kiểu giá trị trong C#

Kiểu giá trị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ểu char
  • 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ị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

Đăng ký theo dõi ủng hộ kênh
Partial, Nested (Bài trước)