Tải bản đầy đủ (.pptx) (20 trang)

Collections & Generics trong C#

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (80.51 KB, 20 trang )

Collections & Generics
Kiểu tập hợp và kiểu tổng quát
Tại sao lại có kiểu tập hợp

Giả sử ta cần nhập 1 danh sách sinh viên để xử lí

Nếu biết trước số sinh viên, ta có thể tạo 1 mảng để chứa danh sách này

Nếu chưa biết trước số sinh viên, ta có thể tạo 1 mảng đủ lớn rồi giới hạn số sinh viên được nhập

Hai cách trên có vẻ hợp lí, nhưng nếu ta muốn nhập thêm 1 sinh viên khi mảng đã đầy thì không thể làm được

Từ đó nảy sinh yêu cầu phải có 1 kiểu dữ liệu nào đó có số phần tử thay đổi được, đó chính là kiểu tập hợp
(Collections)
Kiểu Collection

.NET cung cấp một số class để giải quyết sự giới hạn phần tử của mảng, đó là các lớp collection. Các lớp này được
thiết kế để có số phần tử thay đổi được, nó cung cấp các phương thức để chèn và xóa phần tử trong nó

Có 2 loại kiểu tập hợp:

Kiểu tập hợp không tổng quát (nằm trong các namespace System.Collections, System.Collections.Specialized)

Kiểu tập hợp tổng quát (nằm trong namespace System.Collections.Generics)
Kiểu tập hợp không tổng
quát

Khi nền tảng .NET mới ra đời, các lập trình viên thường dùng các kiểu tập hợp không tổng quát, nằm trong
namespace System.Collections (sau này từ phiên bản .NET 2.0, các kiểu tập hợp này đều được tổng quát hóa và
nằm trong namespace System.Collections.Generics)


Các phần tử trong kiểu tập hợp không tổng quát đều có kiểu là object
Namespace System.Collections
Interface Ý nghĩa
ICollection Định nghĩa các thông số tổng quát của bất kì tập hợp không tổng quát nào
ICloneable Cho phép đối tượng trả về 1 đối tượng là bản sao của nó
IDictionary Cho phép đối tượng nongeneric biểu diễn nội dun của nó bằng cặp key-value
IEnumerable Cho phép trả về 1 đối tượng hiện thực giao diện IEnumerator
IEnumerator Cho phép từ khóa foreach duyệt các phần tử của nó
IList Cho phép thêm, xóa, truy cập phần tử thông qua chỉ số của nó trong dãy
Namespace System.Collections
Class Interface hỗ trợ
(không kể ICollection)
Ý nghĩa
ArrayList IList, IEnumerable, ICloneable Giống như Array nhưng số phần tử của nó có thể tăng lên
nếu cần
Hashtable IDictionary, IEnumerable, ICloneable Tập hợp các cặp giá trị key-value, truy cập value theo key
Queue IEnumerable, ICloneable Tập hợp các đối tượng theo kiểu hàng đợi (_rst-in _rst-out,
FIFO)
SortedList IDictionary, IEnumerable, ICloneable Tập hợp các cặp giá trị key-value, được sắp xếp thứ tự theo
key, có thể truy xuất theo key hoặc theo value
Stack IEnumerable, ICloneable Tập hợp các đối tượng theo kiểu ngăn xếp (last-in _rst-out
LIFO), có các phương thức push và pop
Ví dụ về ArrayList
ArrayList AL = new ArrayList();
AL.Add(“Hello”);
AL.Add(“World”);
AL.Add(“!”);
foreach(string s in AL)
{
Console.WriteLine(“{0} ”, s);

}
// Output
// Hello World !
Các vấn đề của kiểu tập
hợp không tổng quát

Vấn đề về hiệu năng: Khi bạn cần thao tác với các dữ liệu số (hoặc value type), chương trình phải tốn thêm bộ nhớ
để chuyển kiểu value sang kiểu reference lưu trữ trên heap, khi chuyển lại về kiểu value, ta lại tốn them bộ nhớ để
lưu nó trên stack. Những điều trên ảnh hưởng rất lớn đến hiệu năng của chương trình

Vấn đề về an toàn kiểu: Vì kiểu dữ liệu của tập hợp không tổng quát là object nên nó có thể chứa bất kì đối tượng
nào. Khi ta tạo 1 danh sách những chiếc xe, ta phải đảm bảo rằng ta chỉ thêm các đối tượng xe vào trong danh
sách, nếu ta thêm các đối tượng khác, việc biên dịch vẫn thành công nhưng sẽ gây lỗi lúc chạy
Cái nhìn đầu tiên về kiểu
tổng quát
List<Car> carList = new List<Car>();
carList.Add(new Car(“Red”));
carList.Add(new Car(“Green”));
List<int> intList = new List<int>();
intList.Add(1);
// Lệnh sau sẽ gây lỗi
// intList.Add(new Car(“Red”));
Kiểu dữ liệu trừu tượng
public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>,
IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
{
public void Add(T item);
public int BinarySearch(T item);
public bool Contains(T item);
public bool Remove(T item);

public T[] ToArray();

}
Kiểu dữ liệu trừu tượng
public class List<int> : IList<int>, ICollection<int>, IList, ICollection, IReadOnlyList<int>,
IReadOnlyCollection<int>, IEnumerable<int>, IEnumerable
{
public void Add(int item);
public int BinarySearch(int item);
public bool Contains(int item);
public bool Remove(int item);
public int[] ToArray();

}
Kiểu dữ liệu trừu tượng

Kiểu dữ liệu cũng dùng trong các thành viên generic:
Array.Sort<int>(intList);
Array.Sort<Car>(carList);

Giao diện generic
public interface IComparable<T>
{
int CompareTo(T obj);
}
Namespace
System.Collections.Generic
Interface Ý nghĩa
ICollection<T> Định nghĩa các thông số tổng quát của bất kì tập hợp tổng quát nào
IComparer<T> Cho phép đối tượng so sánh với đối tượng khác

IDictionary<TKey, TValue> Cho phép đối tượng generic biểu diễn nội dun của nó bằng cặp key-value
IEnumerable<T> Cho phép trả về 1 đối tượng hiện thực giao diện IEnumerator
IEnumerator<T> Cho phép từ khóa foreach duyệt các phần tử của nó
IList<T> Cho phép thêm, xóa, truy cập phần tử thông qua chỉ số của nó trong dãy
Namespace
System.Collections.Generic
Class Interface hỗ trợ Ý nghĩa
List<T> IList<T>, IEnumerable<T>,
ICollection<T>
Giống ArrayList
Dictionary
<TKey, TValue>
IDictionary<TKey, TValue>, IEnumerable<T> Giống Hashtable
Queue<T> IEnumerable<T>, ICollection Giống Queue
LinkedList<T> IEnumerable<T>, ICollection<T> Danh sách móc nối 2 chiều
Stack<T> IEnumerable<T>, ICollection Giống Stack
SortedDictionary
<TKey, TValue>
ICollection<T>, IDictionary<TKey, TValue>,
IEnumerable<T>
Giống Dictionary + các phần tử được sắp
xếp
Khởi tạo đối tượng
collection

Cú pháp khởi tạo đối tượng này chỉ áp dụng cho các class có phương thức Add
List<int> intList = new List<int> { 1, 2, 4, 5 };
ArrayList myList = new ArrayList { 3, 6, 4, 7 };

Khác với mảng, khi khởi tạo đối tượng collection, ta phải sử dụng từ khóa new

int[] arr = { 0, 1, 3, 7 };
Một vài class generic
collection

List<T>:

Add(T): thêm 1 phần tử vào cuối danh sách

Remove(T): xóa 1 phần tử xuất hiện đầu tiên trong danh sách

Queue<T>:

Dequeue(): trả về phần tử đầu tiên của hàng đợi và xóa nó

Enqueue(T): thêm phần tử vào cuối hàng đợi

Peek(): lấy phần tử đầu tiên của hàng đợi nhưng không xóa nó

Stack<T>:

Push(T): thêm phần tử vào đầu ngăn xếp

Pop(): trả về phần tử đầu tiên của ngăn xếp và xóa nó

Peek(): lấy phần tử đầu tiên của ngăn xếp nhưng không xóa nó
Tự tạo phương thức
generic

Ví dụ ta muốn đổi chỗ 2 đối tượng cùng 1 kiểu, nếu viết theo cách thông thường, ta phải viết từng phương thức
cho từng kiểu dữ liệu. Với generic, ta chỉ cần viết 1 phương thức

static void DoiCho<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}

Khi gọi phương thức này, tùy thuộc vào kiểu của đổi tượng mà ta thay đổi kiểu của T:
DoiCho<int>(ref a, ref b);
DoiCho<Car>(ref car1, ref car2);
Tự tạo class hoặc struct
generic
public class Point<T>
{
public T X { get; set; }
public T Y { get; set; }
public void Draw()
{
Console.WriteLine("{0} {1}", X, Y);
}
public Point() { }
public Point(T xVal, T yVal)
{
X = xVal;
Y = yVal;
}
}
Tương tự như các class hoặc struct bình thường, chỉ
khác là những kiểu dữ liệu được tổng quát hóa thành
kí hiệu T

Từ khóa default

Từ khóa default dùng để lấy giá trị mặc định của 1 kiểu dữ liệu

Nếu đó là kiểu value, nó sẽ trả về 0, hoặc false…

Nếu là kiểu reference, sẽ trả về null
public void ResetData()
{
X = Y = default(T);
}
Giới hạn kiểu dữ liệu trong
generic
Mã giới hạn Ý nghĩa
where T : struct Kiểu T là kiểu value (struct, int, double…)
where T : class Kiểu T là kiểu reference
where T : new() Kiểu T phải có hàm khởi tạo mặc định (không tham số)
where T : tên class Kiểu T phải kế thừa (trực tiếp hoặc gián tiếp) từ class chỉ định
where T : tên interface Kiểu T phải hiện thực giao diện chỉ định
Có thể sử dụng cùng lúc nhiều loại mã giới hạn
public class MyGeneric1<T> where T : struct
public class MyGeneric2<T> where T : class, new()
public class MyGeneric3<T> where T : struct, IPoint
public void Swap<T>(ref T a, ref T b) where T : class

Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Tải bản đầy đủ ngay
×