List<T> trong C#

Ở trong những hướng dẫn trước chúng ta đã tìm hiểu về các non-generic collection trong C# như: ArrayList, SortedList, Hashtable, Stack, QueueBitArray.

Bây giờ chúng ta sẽ chuyển sang tìm hiểu về các generic collection trong C# như: List<T>, Dictionary<TKey, TValue>, SortedList<TKey, TValue>, Hashset<T>, Stack<T> và Queue<T>.

Trong hướng dẫn này, chúng ta sẽ tìm hiểu về List<T> - một generic collection được sử dụng rất phổ biến trong C#.

Sơ đồ sau minh họa hệ thống phân cấp của List<T>.

List<T> trong C#

Như được trình bày trong sơ đồ trên, lớp List<T> triển khai thực hiện tám interface khác nhau cung cấp các chức năng khác nhau. Do đó, đối tượng List<T> có thể được gán cho bất kỳ biến nào có kiểu dữ liệu là các interface trên. Tuy nhiên, nên tạo một đối tượng List<T> và gán nó cho biến kiểu IList<T> hoặc List<T>, như ví dụ bên dưới.

List<int> intList = new List<int>();

//Or

IList<int> intList = new List<int>();

Trong ví dụ trên, câu lệnh đầu tiên khai báo biến sử dụng List<T>, trong khi câu lệnh thứ hai khai báo biến sử dụng IList<T>.

Lớp List<T> là một triển khai thực hiện của giao diện IList<T>. Trong lập trình hướng đối tượng, nên sử dụng interface thay vì sử dụng trực tiếp lớp triển khai thực hiện. Vì vậy, nên sử dụng biến kiểu IList <T> để tạo một đối tượng List<T>.

Tuy nhiên, lớp List<T> bao gồm nhiều phương thức hỗ trợ hơn giao diện IList<T>. Phần tiếp theo sẽ trình bày các thuộc tính và phương thức quan trọng của lớp List<T>:

Các thành viên quan trọng của List<T>

Các thuộc tính quan trọng của List<T>:

Thuộc tính Miêu tả
Items Trả về hoặc thiết lập phần tử ở chỉ mục đã chỉ định
Count Trả về tổng số phần tử tồn tại trong List<T>

Các phương thức quan trọng của List<T>:

Phương thức Miêu tả
Add Thêm một phần tử vào cuối List<T>.
AddRange Thêm các phần tử của một collection được chỉ định vào cuối List<T>.
BinarySearch Tìm kiếm phần tử và trả về một chỉ mục của phần tử.
Clear Xóa tất cả các phần tử khỏi List<T>.
Contains Kiểm tra xem phần tử được chỉ định có tồn tại trong List<T> hay không.
Find Tìm phần tử đầu tiên dựa trên biểu thức đã chỉ định.
Foreach Duyệt qua một List<T>.
Insert Chèn một phần tử vào chỉ mục được chỉ định trong List<T>.
InsertRange Chèn các phần tử của bộ sưu tập khác vào chỉ mục được chỉ định.
Remove Loại bỏ phần tử đầu tiên của phần tử được chỉ định.
RemoveAt Loại bỏ phần tử tại chỉ mục được chỉ định.
RemoveRange Loại bỏ tất cả các phần tử phù hợp với biểu thức được cung cấp.
Sort Sắp xếp tất cả các phần tử.
TrimExcess Thiết lập kích thước List<T> bằng với số phần tử thực tế.
TrueForALL Xác định xem tất cả phần tử trong List<T> có khớp với các điều kiện được định nghĩa trong biểu thức hay không.

Thêm các phần tử vào List<T>

Phương thức Add

Sử dụng phương thức Add() để thêm một phần tử vào List<T>. Ví dụ sau đây minh họa thêm giá trị vào List<T>:

IList<int> intList = new List<int>();
intList.Add(10);
intList.Add(20);
intList.Add(30);
intList.Add(40);

Console.WriteLine(intList.Count);

IList<string> strList = new List<string>();
strList.Add("one");
strList.Add("two");
strList.Add("three");
strList.Add("four");
strList.Add("four");
strList.Add(null);
strList.Add(null);

Console.WriteLine(strList.Count);

IList<Student> studentList = new List<Student>();
studentList.Add(new Student());
studentList.Add(new Student());
studentList.Add(new Student());

Console.WriteLine(studentList.Count);

Đây là kết quả khi biên dịch và chạy chương trình:

4
7
3

Bạn cũng có thể thêm các phần tử tại thời điểm khởi tạo bằng cú pháp khởi tạo đối tượng như sau:

IList<int> intList = new List<int>() { 10, 20, 30, 40 };

//Or

IList<Student> studentList = new List<Student>() 
{ 
	new Student() { Id = 1, Name = "Bill" },
	new Student() { Id = 2, Name = "Steve" },
	new Student() { Id = 3, Name = "Ram" },
	new Student() { Id = 4, Name = "Moin" }
};

Phương thức AddRange

Sử dụng phương thức AddRange() để thêm tất cả các phần tử của một collection khác.

Ví dụ sau minh họa thêm phần tử vào List<T> sử dụng phương thức AddRange:

IList<int> list1 = new List<int>();

list1.Add(10);
list1.Add(20);
list1.Add(30);
list1.Add(40);

List<int> list2 = new List<int>();

list2.AddRange(list1);

Console.WriteLine(list2.Count);

Đây là kết quả khi biên dịch và chạy chương trình:

4
Lưu ý: Phương thức AddRange() sẽ chỉ được áp dụng nếu bạn khởi tạo biến kiểu List<T>. IList<T> không có phương thức AddRange().

Truy cập phần tử trong List<T>

Sử dụng phương thức ForEach

Sử dụng phương thức ForEach để duyệt qua các phần tử của List<T>.

List<int> list = new List<int>() { 10, 20, 30, 40, 50 };

list.ForEach(item => Console.WriteLine(item));

Đây là kết quả khi biên dịch và chạy chương trình:

10
20
30
40
50

Sử dụng vòng lặp foreach

Nếu bạn đã khởi tạo List<T> rồi gắn cho biến kiểu IList<T> thì hãy sử dụng câu lệnh foreach để duyệt các phần tử trong collection như sau:

IList<int> list = new List<int>() { 10, 20, 30, 40 };

foreach (var item in list)
{
    Console.WriteLine(item);
}

Đây là kết quả khi biên dịch và chạy chương trình:

10
20
30
40

Truy cập từng phần tử bằng cách sử dụng một bộ chỉ mục:

IList<int> list = new List<int>() { 10, 20, 30, 40 };

int elem = list[1]; // returns 20

Sử dụng thuộc tính Count để lấy tổng số phần tử trong List<T>.

IList<int> intList = new List<int>() { 10, 20, 30, 40 };

Console.Write("Total elements: {0}", intList.Count);

Đây là kết quả khi biên dịch và chạy chương trình:

Total elements: 4

Sử dụng vòng lặp for

Sử dụng vòng lặp for để duyệt List<T> như hình dưới đây:

IList<int> list = new List<int>() { 10, 20, 30, 40 };

int length = list.Count;
for (int i = 0; i < length; i++)
{
    Console.WriteLine(list[i]);
}

Đây là kết quả khi biên dịch và chạy chương trình:

10
20
30
40

Lớp List<T> triển khai thực hiện interface IList<T>, vì vậy List<T> được ép kiểu ngầm định về IList<T>. Hãy xem ví dụ sau:

static void Print(IList<string> list)
{
    Console.WriteLine("Count: {0}", list.Count);
    foreach (string item in list)
    {
        Console.WriteLine(item);
    }
}

static void Main(string[] args)
{
    string[] array = new string[2];
    array[0] = "Hello";
    array[1] = "World";
    Print(array);

    List<string> list = new List<string>();
    list.Add("Hello");
    list.Add("World");
    list.Add("from");
    list.Add("Comdy");
    Print(list);
}

Đây là kết quả khi biên dịch và chạy chương trình:

Hello
World
Hello
World
from
Comdy

Chèn phần tử vào List<T>

Sử dụng phương thức Insert() để chèn một phần tử vào List<T> tại vị trí đã chỉ định.

IList<int> list = new List<int>() { 10, 20, 30, 40 };

list.Insert(1, 11);// inserts 11 at 1st index: after 10.

foreach (var item in list)
{
    Console.Write(item);
}

Đây là kết quả khi biên dịch và chạy chương trình:

10
11
20
30
40

Xóa phần tử khỏi List<T>

Các phương thức Remove()RemoveAt() được sử dụng để xóa phần tử khỏi  List<T>.

Phương thức Remove() sẽ xóa một phần tử trong List<T> có giá trị trùng với giá trị được chỉ định.

Phương thức RemoveAt() sẽ xóa phần tử tại vị trí được chỉ định trong List<T>.

IList<int> list = new List<int>(){ 10, 20, 30, 40 };

list.Remove(10); // removes the 10 from a list

list.RemoveAt(2); //removes the 3rd element (index starts from 0)

foreach (var item in list)
{
    Console.Write(item);
}

Đây là kết quả khi biên dịch và chạy chương trình:

20
30

Phương thức TrueForAll

TrueForAll() là một phương thức của lớp List<T>, nó trả về true nếu biểu thức điều kiện được chỉ định là true, ngược lại là false. Ở đây, biểu thức điều kiện có thể được chỉ định là delegate hoặc biểu thức lambda .

List<int> intList = new List<int>(){ 10, 20, 30, 40 };

bool res = intList.TrueForAll(el => el % 2 == 0);// returns true

Ví dụ sau sử dụng phương thức IsPositiveInt() làm tham số cho TrueForAll.

static bool IsPositiveInt(int i)
{
    return i > 0;
}

static void Main(string[] args)
{
    List<int> list = new List<int>() { 10, 20, 30, 40 };

    bool res = list.TrueForAll(IsPositiveInt);
}

Truy cập MSDN để biết thêm thông tin về các phương thức & thuộc tính của IList<T> hoặc List<T>.

Những điểm cần nhớ:

  • List<T> lưu trữ các phần tử của kiểu dữ liệu đã chỉ định và nó tự động phát triển kích thước.
  • List<T> có thể lưu trữ nhiều phần tử null và trùng lặp.
  • List<T> có thể được gán cho loại biến kiểu IList<T> hoặc List<T>. Nó cung cấp thêm phương thức trợ giúp hữu ích khi được gán cho biến kiểu List<T>.
  • List<T> có thể được truy cập bằng cách sử dụng bộ chỉ mục, phương thức ForEach, câu lệnh lặp for hoặc foreach.
  • LINQ có thể được sử dụng để truy vấn List<T>.
  • List<T> rất lý tưởng để lưu trữ và truy xuất số lượng lớn các phần tử.

Ở hướng dẫn tiếp theo chúng ta sẽ tìm hiểu về lớp Dictionary<TKey,TValue> trong C#.

Dictionary<TKey, TValue> trong C# | Comdy
Dictionary<TKey, TValue> trong C# là gì? Dictionary<TKey, TValue> trong C# dùng để làm gì? Cách sử dụng Dictionary<TKey, TValue> trong C#.


Bài viết liên quan:

Hướng dẫn này sẽ giúp bạn tìm hiểu về đọc ghi file (File I/O) trong C# và sử dụng các lớp tiện ích để đọc ghi file.

Reflection trong C#

  • 6 min read

Reflection trong C# là gì? Ứng dụng của Reflection trong C#. Cách khai báo và sử dụng Reflection trong C#.

Attribute trong C#

  • 7 min read

Attribute trong C# là gì? Có những loại attribute nào trong C#? Làm sao để sử dụng attribute trong C#.