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

Sử dụng struct trong C#

struct kiểu dữ liệu cấu trúc (còn gọi là structure) - kiểu dữ liệu này tạo thành khi ta muốn gộp các dữ liệu có liên quan thành một nhóm (đóng gói dữ liệu). Để tạo ra kiểu dữ liệu cấu trúc dùng đến từ khóa struct với khai báo khá giống khai báo lớp, tuy nhiên struct là thuộc nhóm kiểu giá trị C# chứ không phải kiểu tham chiếu C# (Do đó, truyền tham số dùng struct là tham trị: xem thêm tham chiếu, tham trị C# ). Trong struct có thể chứa: trường dữ liệu, thuộc tính, phương thức khởi tạo, hằng số, các phương thức, toán tử, sự kiện.

Thông thường sử dụng struct để gộp một nhóm nhỏ các dữ liệu, mục đích chính là lưu trữ dữ liệu rất hạn chế tạo ra các ứng xử trên struct (các phương thức).

Bắt đầu bằng một ví dụ đơn giản về struct, khai báo một cấu trúc - có 2 trường dữ liệu (không phải thuộc tính) và một phương thức

public struct Product {

    public string name;   // trường tên sản phẩm
    public decimal price; // trường giá sản phẩm

    // Phương thức sinh ra chuỗi thông tin
    public override string ToString() => $"{name} : {price}$";

}

Do là kiểu giá trị với các trường dữ liệu, nên có thể khai báo - khởi tạo các trường và sử dụng như kiểu giá trị:

Product  productA;
Product productA;
productA.name = "Iphone";
productA.price = 1000;

Product productB = productA; // gán struct, là sao chép giá trị chứ không tham chiếu như lớp
productB.name = "Laptop";

Console.WriteLine(productA.ToString());
Console.WriteLine(productB.ToString());
// In ra:
// Iphone : 1000$
// Laptop : 1000$

Phương thức khởi tạo struct

Trong struct cũng có thể có phương thức khởi tạo như lớp, nó dùng để khởi tạo giá trị các trường hoặc thuộc tính. Khi có phương thức khởi tạo (hàm tạo) muốn chạy nó thì phải dùng toán tử new để có bản thực thi của struct. Một lưu ý nữa là phương thức khởi tạo bắt buộc phải khởi tạo toàn bộ thành viên dữ liệu (trường, thuộc tính) có trong struct. Ví dụ:

public struct Product {

    public Product(string _name)
    {
      // trong cấu trúc có bao nhiêu trường dữ liệu, thuộc tính
      // phải khởi tạo hết trong hàm tạo (thiếu sẽ lỗi)
      name = _name;
      price = 100;
    }

    public string name;   // trường tên sản phẩm
    public decimal price; // trường giá sản phẩm

    // Phương thức sinh ra chuỗi thông tin
    public override string ToString() => $"{name} : {price}$";

}

Thi hành hàm tạo thì phải dùng tới new, như đoạn code:

Product product = new Product("Samsung Abc");
Console.WriteLine(product.ToString());
// Samsung Abc : 100$

Thuộc tính trong struct

Trong struct cũng có thể khai báo các thuộc tính, chỉ cần lưu ý đã có thuộc tính thì bắt buộc phải khởi tạo nó một cách tường minh trong phương thức khởi tạo nếu không sẽ lỗi. Ví dụ sau có hai thuộc tính là NameDescription

public struct Product {

    public Product(string _name)
    {
      name = _name;  // đồng nghĩa khởi tạo thuộc tính Name
      price = 100;
      Description = "Mô tả về sản phẩm {name}";
    }

    public string name;   // trường tên sản phẩm
    public decimal price; // trường giá sản phẩm

    // Phương thức sinh ra chuỗi thông tin
    public override string ToString() => $"{name} : {price}$";

    // Thuộc tính Name
    public string Name {set => name = value; get => name;}
    // Thuộc tính Description
    public string Description {set; get;}

}

So sánh sự khác nhau giữa class và struct

  • Struct phù hợp khi muốn gom một lượng nhỏ các biến có kiểu nguyên thủy (int, float ...), thuộc tính lại với nhau. Class thì dùng khi các diễn tả đối tượng chứa các biến, thuộc tính và xử lý dữ liệu phức tạp.
  • Struct có thể dùng khai báo biến mà không cần thao tác tạo đối tượng. BIẾN KIỂU STRUCT LÀ THAM TRỊ CÒN BIẾN CLASS LÀ THAM CHIẾU . struct được lưu ở bộ nhớ stack, còn đối tượng được sinh ra bới class được lưu ở bộ nhớ heap - bộ nhớ heap được quản lý, giám sát, thu hồi tự động bởi GC.

Sử dụng kiểu liệt kê (Enumeration Type) - enum

Kiểu liệt kê (enum) khai báo một tập hợp các hằng số có tên, mặc định giá trị các hằng số này là kiểu int và bắt đầu từ 0 trở đi trong khai báo kiểu liệt kê. Liệt kê (enum) thuộc dạng kiểu giá trị như struct. Để khai báo một kiểu liệt kê thì dùng từ khóa enum

Ví dụ - khai báo kiểu liệt kê thể hiện học lực của sinh viên gồm có: Kém (0), Trung bình (1), Khá (2), Giỏi (3)

enum HocLuc {Kem, TrungBinh, Kha, Gioi};

Mặc định enum sẽ thiết lập tên các khai báo sẽ nhận giá trị tương ứng từ 0, 1, 2 ... Tuy nhiên, bạn có thể gán một tên nào đó ứng với giá trị cụ thể, ví dụ TrungBinh nhận giá trị 5

enum HocLuc {Kem, TrungBinh = 5, Kha, Gioi};

Do TrungBinh bằng 5, nên tên tiếp theo Kha sẽ nhận 6, Giỏi là 7

Để nhận giá trị liệt kê - bạn dùng toán tử . rồi đến tên phần tử.

enum HocLuc {Kem, TrungBinh, Kha, Gioi}

static void Main(string[] args)
{
    int a = (int)HocLuc.Kha;  // cast enum thành int
    Console.WriteLine(a);     // 2
}

Khai báo kiểu enum rất phù hợp khi giá trị của biến nhận một giá trị hằng số trong tập hằng số hữu hạn nào đó, như danh sách các ngày trong tuần, trạng thái online / offline, và đặc biệt hay dùng Enum với câu lệnh switch

static void test_enum () {

    HocLuc hocluc = HocLuc.Kha; // khai báo biến hocluc kiểu enum và khởi tạo giá trị bằng HocLuc.Kha
    switch (hocluc) {
        case HocLuc.Kem:
            Console.WriteLine ("Học lực kém");
            break;
        case HocLuc.Kha:
            Console.WriteLine ("Học lực Kha");
            break;
        case HocLuc.Gioi:
            Console.WriteLine ("Học lực Giỏi");
            break;
        default:
            Console.WriteLine ("Học lực TB");
            break;

    }
}

Bạn có thể cast - chuyển kiểu qua lại giữa enum và int

HocLuc hoc = (HocLuc)2;
Console.WriteLine(hoc); //Kha

Sử dụng enum, khi viết code tên của Enum nó đã gợi nhớ giá trị - ý nghĩa của dữ liệu nên code dễ đọc, dễ hiểu hơn

HocLuc hocluc_hocsinhA = HocLuc.Kha;
int    hocluc_hocsinhB = 2;

Hai dòng code trên, về logic có thể hoàn toàn giống nhau. Nhưng đọc code ở dòng 1 sẽ dễ hơn đọc ở dòng 2 nhiều.

Tham khảo mã nguồn CS022_struct_and_enum (git) hoặc tải về ex022