Nhìn tiêu đề chắc nhiều bạn nghĩ rằng mình đã biết và hiểu hết các kiểu dữ liệu trong C#, tuy nhiên có nhiều kiểu dữ liệu cũng như cách phân loại mà không phải bạn nào cũng để ý hay nhớ đến. Các kiểu dữ liệu trong C# được chia làm 3 kiểu chính:


  1. Value Types
  2. Reference Types
  3. Pointer Types

Value Types (Kiểu giá trị)


Value Types còn được chia làm 2 loại, đó là Structs và Enumerations


Structs là gì?


Structs bao gồm các kiểu dữ liệu sau đây:



  1. Numeric types
    1. Integral types (Bao gồm các kiểu dữ liệu cơ bản như int, char, long, …)
    2. Floating-point types (Bao gồm các kiểu dữ liệu có chấm động như float, double)
    3. Decimal (Là kiểu dữ liệu thập phân, có giá trị trong khoảng (-7.9 x 1028 đến 7.9 x 1028) / (100 đến 28))

  2. Bool (kiểu dữ liệu trả về true / false)
  3. User defined structs (Các kiểu dữ liệu mà người dùng tự định nghĩa)





Tên kiểu



Khoảng giá trị



Biểu diễn



sbyte



-128 đến 127



Signed 8-bit integer



byte



0 đến 255



Unsigned 8-bit integer



char



U+0000 đến U+ffff



Unicode 16-bit character



short



-32,768 đến 32,767



Signed 16-bit integer



ushort



0 đến 65,535



Unsigned 16-bit integer



int



-2,147,483,648 đến 2,147,483,647



Signed 32-bit integer



uint



0 đến 4,294,967,295



Unsigned 32-bit integer



long



-9,223,372,036,854,775,808 đến 9,223,372,036,854,775,807



Signed 64-bit integer



ulong



0 đến 18,446,744,073,709,551,615



Unsigned 64-bit integer



float



±1.5e−45 đến ±3.4e38


7 digits

double


±5.0e−324 đến ±1.7e308

15-16 digits



decimal


(-7.9 x 1028 đến 7.9 x 1028) / (100 đến 28)

28-29 significant digits



 


Các biến kiểu giá trị (Value Types) có thể được gán một giá trị một cách trực tiếp. Chúng được kế thừa từ lớp System.ValueType.


  • Để lấy kích cỡ chính xác của 1 kiểu / 1 biến trên 1 nền tảng cụ thể nào đó thì bạn có thể dùng hàm sizeof(type)
  • Để xác định kiểu dữ liệu của 1 biến thì bạn có thể dùng hàm typeof(biến)

 


Cách khai báo:


type var_name;
type var_name = default_value;

Ví dụ:


 int x = 5;
 int y;

// Unsigned và signed khác nhau ở chỗ là unsigned chỉ lưu trữ giá trị >= 0 còn signed thì chứa cả giá trị < 0
byte b = 1; // Dùng kiểu byte khi cần lưu trữ 1 số nguyên nhỏ, thông thường là số có giá trị < 128
sbyte sb = -1; // Dùng sbyte khi cần lưu trữ 1 số nguyên nhỏ nhưng nằm trong khoảng -128 đến 127

short s = 1000; // Dùng short khi cần lưu trữ 1 số nguyên < 32768 và ushort khi lưu số trong khoảng -32768 đến 32767

int i = 1000000; // Dùng int khi cần lưu trữ số nguyên trong khoảng -2,147,483,648 đến 2,147,483,647
uint ui = 100000; // Dùng uint khi cần lưu trữ số nguyên lớn hơn 0 và nhỏ hơn 2,147,483,648

long l = 123456789; // Dùng long khi cần lưu trữ số nguyên khá lớn, trong khoảng -9,223,372,036,854,775,808 đến 9,223,372,036,854,775,807, cũng tương tự với ulong

float fl = 3e38; // Dùng float hoặc double khi cần lưu trữ số có dấu chấm động

decimal dec = 7.9M; // Dùng decimal để lưu trữ số thập phân có độ chính xác rất cao (28 chữ số thập phân), khi khai báo cần có hậu tố m hoặc M
 

 


Enumeration Types


Enumeration là kiểu dữ liệu cho phép chúng ta lưu trữ các giá trị mà không trùng nhau cũng như có thể truy cập trực tiếp thông qua flag của chúng.


enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
enum Months : byte { Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec }; 

Days today = Days.Monday;
int dayNumber =(int)today;
Console.WriteLine("{0} là ngày có số #{1}.", today, dayNumber);

Months thisMonth = Months.Jan;
byte monthNumber = (byte)thisMonth;
Console.WriteLine("{0} là tháng có số #{1}.", thisMonth, monthNumber);

// Output:
// Monday là ngày có số #1.
// Dec là tháng có số #0.

 


Reference Types (Kiểu dữ liệu tham chiếu)


            Kiểu dữ liệu tham chiếu không chứa trực tiếp giá trị nào đó, mà nó chứa 1 tham chiếu đến giá trị đó. Ví dụ dễ hiểu: Bạn có một ngôi nhà trị giá 1 tỉ USD. Bạn muốn gán giá trị ngôi nhà vào 1 biến với kiểu giá trị thì biến đó sẽ lưu trữ là 1 tỉ USD. Tuy nhiên nếu bạn gán ngôi nhà bằng một kiểu dữ liệu tham chiếu, thì biến đó sẽ tham chiếu hay nói cách khác là nó lưu địa chỉ của ngôi nhà của bạn.


            Vậy kiểu dữ liệu tham chiếu là gì? Là kiểu dữ liệu tham chiếu đến một vị trí bộ nhớ, và nó lưu địa chỉ của bộ nhớ đó.


            Cú pháp để bạn khai báo một kiểu dữ liệu tham chiếu:



  • Class
  • Interface
  • Delegate


Ngoài ra C# cũng hỗ trợ sẵn một số kiểu dữ liệu tham chiếu:



  • Dynamic
  • Object
  • String


 


Kiểu Dynamic


            Đây là một kiểu dữ liệu tham chiếu mà C# hỗ trợ sẵn cho chúng ta sử dụng. Với kiểu dữ liệu Dynamic thì bạn có thể lưu trữ bất kì kiểu dữ liệu gì bên trong nó và nó chỉ được kiểm tra khi runtime mà thôi.


 


 Kiểu Dymanic thường được dùng khi mà bạn cần bỏ qua việc kiểm tra kiểu dữ liệu khi code hay compile. Tuy nhiên cần lưu ý khi sử dụng kiểu dynamic có thể dẫn đến crash ứng dụng của bạn. Vì thế nên hạn chế dùng Dynamic nếu như bạn không chắc chắn kết quả.


Cách khai báo:


dynamic var_name = value;

Ví dụ:


dynamic x = 5;

 


Kiểu Object


            Kiểu Object là một kiểu dữ liệu cơ bản cho tất cả các kiểu dữ liệu trong C#. Tất cả kiểu dữ liệu trong C# đều kế thừa trực tiếp hoặc gián tiếp tới System.Object (Ngoại trừ Pointer Type).


            Khi một kiểu dữ liệu giá trị được chuyển đổi thành Object thì được gọi là Boxing, còn chuyển đổi từ Object thành kiểu dữ liệu giá trị thì gọi là Unboxing


 


Kiểu String


          Kiểu String cho phép bạn gán chuỗi vào 1 biến. Kiểu String được kế thừa từ System.String và System.String lại kế thừa từ System.Object.


Cách khai báo:


string var_name = default_value;

Ví dụ:


string name = "Pham Quoc Thang";

Pointer Type (Kiểu dữ liệu con trỏ)


            Kiểu dữ liệu con trỏ chỉ được dùng trong chế độ unsafe mà thôi, nghĩa là với C# thì kiểu dữ liệu con trỏ là một kiểu dữ liệu không an toàn. Bởi vì khi sử dụng một kiểu dữ liệu con trỏ thì bạn có khả năng cấp phát động, vì thế bạn phải chủ động thu hồi lại bộ nhớ đã cấp phát. C# cũng có tự động thu hồi cho bạn, nhưng với kiểu dữ liệu con trỏ thì nó không triệt để, nên vì thế C# xếp nó vào unsafe.


            Kiểu dữ liệu con trỏ lưu trữ địa chỉ của bộ nhớ. Tuy nhiên kiểu dữ liệu con trỏ không kế thừa từ Object và không có mối quan hệ nào giữa kiểu dữ liệu con trỏ và object. Vì thế boxing và unboxing cũng không được hỗ trợ trên kiểu dữ liệu con trỏ. Ngoài ra, bạn cũng có thể chuyển đổi kiểu dữ liệu của con trỏ


 


 Cách khai báo:


type* var_name;

Ví dụ:


int* x;