Kiểm tra hệ thống loại .NET

Đã hoàn thành

C# là một ngôn ngữ được nhập mạnh. Mỗi biến và hằng số đều có một loại, giống như mọi biểu thức định trị thành một giá trị. Thư viện lớp .NET xác định các kiểu số và kiểu phức hợp dựng sẵn đại diện cho nhiều cấu trúc khác nhau. Những cấu trúc này bao gồm hệ thống tệp, kết nối mạng, bộ sưu tập và mảng đối tượng và ngày tháng. Một chương trình C# điển hình sử dụng các loại từ thư viện lớp và các loại do người dùng xác định mô hình các khái niệm cụ thể cho miền vấn đề của chương trình.

Các loại tích hợp sẵn

C# cung cấp một tập hợp các loại tích hợp sẵn tiêu chuẩn. Các kiểu chuẩn này đại diện cho số nguyên, giá trị điểm trôi nổi, biểu thức Boolean, ký tự văn bản, giá trị thập phân và các kiểu dữ liệu khác. Ngoài ra còn có kiểu chuỗi và đối tượng dựng sẵn. Những loại này có sẵn để bạn sử dụng trong bất kỳ chương trình C# nào.

Các loại tùy chỉnh

Bạn sử dụng cấu trúc struct, class, interface, enumrecord để tạo các loại tùy chỉnh của riêng bạn. Bản thân thư viện lớp .NET là một tập hợp các loại tùy chỉnh mà bạn có thể sử dụng trong các ứng dụng của riêng bạn. Theo mặc định, các loại thường được sử dụng nhất trong thư viện lớp có sẵn trong bất kỳ chương trình C# nào. Những người khác trở nên sẵn dùng chỉ khi bạn rõ ràng thêm một tham chiếu dự án vào tổ hợp xác định chúng. Sau khi trình biên dịch có một tham chiếu đến hợp ngữ, bạn có thể khai báo các biến (và hằng số) của các loại khai báo trong hợp ngữ đó trong mã nguồn.

Hệ thống loại thông thường

Điều quan trọng là phải hiểu hai điểm cơ bản về hệ thống loại trong .NET:

  • Nó hỗ trợ nguyên tắc thừa kế. Các loại có thể bắt nguồn từ các loại khác, được gọi là loại cơ sở. Loại dẫn xuất kế thừa (với một số hạn chế) các phương pháp, thuộc tính và các thành viên khác của loại cơ sở. Loại cơ sở lần lượt có thể bắt nguồn từ một số loại khác, trong trường hợp đó loại dẫn xuất kế thừa các thành viên của cả hai loại cơ sở trong cấu trúc phân cấp kế thừa của nó. Tất cả các kiểu, bao gồm các loại số tích hợp sẵn như System.Int32 (từ khóa C#: int), cuối cùng đều bắt nguồn từ một kiểu cơ sở duy nhất là System.Object (từ khóa C#: object). Cấu trúc phân cấp kiểu hợp nhất này được gọi là Hệ thống Loại Chung (CTS).

  • Mỗi kiểu trong CTS được xác định là kiểu giá trị hoặc loại tham chiếu. Những loại này bao gồm tất cả các loại tùy chỉnh trong thư viện lớp .NET và cả các loại do người dùng xác định của riêng bạn. Các loại mà bạn xác định bằng cách sử dụng từ khóa struct là các loại giá trị; tất cả các kiểu số tích hợp sẵn đều là các cấu trúc. Các kiểu bạn xác định bằng cách sử dụng lớp hoặc từ khóa bản ghi là các loại tham chiếu. Kiểu tham chiếu và kiểu giá trị có quy tắc thời gian biên dịch khác nhau và hành vi thời gian chạy khác nhau.

Minh họa sau đây cho thấy mối quan hệ giữa các loại giá trị và kiểu tham chiếu trong CTS.

đồ hiển thị các loại giá trị và tham chiếu.

Lớp và cấu trúc là hai trong số các cấu trúc cơ bản của hệ thống loại phổ biến trong .NET. Về cơ bản, mỗi cấu trúc dữ liệu đóng gói một tập hợp dữ liệu và hành vi thuộc về nhau như một đơn vị lô-gic. Dữ liệu và hành vi là các thành viên của class, struct, hoặc record. Các thành viên của một lớp bao gồm thuộc tính (dữ liệu), phương pháp (hành vi), trường (các biến được khai báo bên trong lớp) và nhiều khác.

Khai báo class, struct, hoặc record giống như một bản thiết kế được sử dụng để tạo các phiên bản hoặc đối tượng vào thời gian chạy. Nếu bạn xác định một lớp có Person, Person đó là tên của kiểu. Nếu bạn khai báo và khởi tạo một biến p loại Person, p được cho là một đối tượng hoặc trường hợp của các Person. Có thể tạo nhiều phiên bản cùng loại Person thể được tạo và mỗi phiên bản có thể có các giá trị khác nhau trong thuộc tính và trường của nó.

Lớp là kiểu tham chiếu. Khi một đối tượng của loại được tạo ra, các biến mà các đối tượng được gán giữ chỉ là một tham chiếu đến bộ nhớ đó. Khi tham chiếu đối tượng được gán cho một biến mới, biến mới tham chiếu đến đối tượng ban đầu. Những thay đổi được thực hiện thông qua một biến số được phản ánh trong biến số khác vì cả hai đều tham chiếu đến cùng một dữ liệu.

Giá struct là một loại giá trị. Khi một struct được tạo ra, các biến mà các struct được chỉ định giữ dữ structthực tế của bạn. Khi giá struct được gán cho một biến mới, giá trị dữ liệu sẽ được sao chép. Biến mới và biến gốc do đó chứa hai bản sao riêng biệt của cùng một dữ liệu. Những thay đổi được thực hiện cho một bản sao không ảnh hưởng đến bản sao còn lại.

Các loại bản ghi có thể là loại tham chiếu (record class) hoặc loại giá trị (record struct). Các loại bản ghi chứa các phương pháp hỗ trợ bình đẳng giá trị.

Nói chung, các lớp được sử dụng để mô hình hóa hành vi phức tạp hơn. Các lớp thường lưu trữ dữ liệu được dự định sẽ được thay đổi sau khi tạo đối tượng lớp. Cấu trúc phù hợp nhất cho các cấu trúc dữ liệu nhỏ. Các cấu trúc thường lưu trữ dữ liệu không nhằm mục đích được sửa đổi sau struct được tạo. Loại bản ghi là cấu trúc dữ liệu với các thành viên tổng hợp trình biên dịch khác. Bản ghi thường lưu trữ dữ liệu không nhằm mục đích được sửa đổi sau khi tạo đối tượng.

Các loại giá trị

Các loại giá trị bắt nguồn từ System.ValueType, bắt nguồn từ một System.Object. Các loại bắt nguồn từ ngôn System.ValueType hành vi đặc biệt trong thời gian chạy ngôn ngữ chung. Các biến loại giá trị trực tiếp chứa giá trị của chúng. Bộ nhớ cho một struct được phân bổ tại chỗ trong bất kỳ bối cảnh biến được khai báo. Không có phân bổ đống riêng biệt hoặc rác bộ sưu tập chi phí cho các biến loại giá trị. Bạn có thể khai báo các kiểu cấu trúc bản ghi là kiểu giá trị và bao gồm các phần tử tổng hợp cho bản ghi.

Có hai loại giá trị: struct và enum.

Các kiểu số tích hợp sẵn là các cấu trúc và chúng có các trường và phương pháp mà bạn có thể truy nhập:


// constant field on type byte.
byte b = byte.MaxValue;

Tuy nhiên, bạn khai báo và gán giá trị cho chúng như thể chúng là các loại không tổng hợp đơn giản:


byte num = 0xA;
int i = 5;
char c = 'Z';

Các loại giá trị được dấu. Bạn không thể lấy một loại từ bất kỳ loại giá trị nào, ví dụ: System.Int32. Bạn không thể xác định một struct kế thừa từ bất kỳ class hoặc struct do người dùng xác định vì struct chỉ có thể kế thừa từ System.ValueType.

Bạn sử dụng từ khóa struct để tạo các loại giá trị tùy chỉnh của riêng bạn. Thông thường, một cấu trúc được sử dụng như một bộ chứa cho một tập hợp nhỏ các biến liên quan, như minh họa trong ví dụ sau đây:


public struct Coords
{
    public int x, y;

    public Coords(int p1, int p2)
    {
        x = p1;
        y = p2;
    }
}

Thể loại các loại giá trị khác là enum. Một enum định nghĩa một tập hợp các hằng số nguyên đã đặt tên. Ví dụ, liệt System.IO.FileMode trong thư viện lớp .NET chứa một tập hợp các số nguyên hằng số đã đặt tên chỉ rõ cách mở tệp. Cú pháp cho một tài enum được hiển thị trong ví dụ sau đây:


public enum FileMode
{
    CreateNew = 1,
    Create = 2,
    Open = 3,
    OpenOrCreate = 4,
    Truncate = 5,
    Append = 6,
}

Hằng System.IO.FileMode.Create có giá trị là 2. Tuy nhiên, tên gọi này có ý nghĩa hơn nhiều đối với con người khi đọc mã nguồn và vì lý do đó tốt hơn là nên sử dụng các liệt kê thay vì các số chữ cố định.

Tất cả enums kế từ System.Enum, kế thừa từ System.ValueType. Tất cả các quy tắc áp dụng cho structs cũng áp dụng cho enums.

Loại tham chiếu

Các kiểu class, record, delegate, arrayinterface là các loại tham.

Khi bạn khai báo một biến của một loại tham chiếu, nó chứa giá trị null cho đến khi bạn gán nó với một thể hiện của loại đó hoặc tạo một bằng cách sử dụng toán tử new.

Ví dụ sau đây minh họa cách khai báo các biến loại tham chiếu sử dụng mảng:


// Declaring an array variable
int[] numbers;

// Initializing the array with a size of 5
numbers = new int[5];

// Alternatively, declaring and initializing an array in one line
int[] numbers2 = new int[] { 1, 2, 3, 4, 5 };

// Assigning a reference to another variable
int[] numbers3 = numbers2;

Toán tử new tạo thể hiện của kiểu và trả về tham chiếu đến phiên bản đó. Tham chiếu là địa chỉ bộ nhớ của đối tượng và tham chiếu đó được lưu trữ trong biến số. Khi bạn gán biến loại tham chiếu cho một biến khác, bạn đang sao chép tham chiếu, chứ không phải chính đối tượng đó. Cả hai biến tham chiếu đến cùng một đối tượng trong bộ nhớ.

Ghi

Ngoài các kiểu tham chiếu, mảng còn là bộ sưu tập. Bộ sưu tập có thể được khởi tạo bằng cách sử dụng biểu thức bộ sưu tập, loại bỏ yêu cầu bao gồm từ khóa new khi khai báo và khởi tạo mảng trong một dòng. Ví dụ: int[] numbers = [ 1, 2, 3, 4, 5 ];.

Bạn có thể tạo một phiên bản của lớp bằng cách sử dụng cùng một cú pháp được sử dụng để thuyết trình các kiểu dựng sẵn. Ví dụ sau đây minh họa cách tạo phiên bản của lớp học:


MyClass myClass = new MyClass();
MyClass myClass2 = myClass;

Toán tử new tạo một thể hiện của lớp và trả về tham chiếu đến phiên bản đó. Tham chiếu là địa chỉ bộ nhớ của đối tượng và tham chiếu đó được lưu trữ trong biến số. Khi bạn gán biến loại tham chiếu cho một biến khác, bạn đang sao chép tham chiếu, chứ không phải chính đối tượng đó. Cả hai biến tham chiếu đến cùng một đối tượng trong bộ nhớ.