Ví dụ 9.10 thì tương tự như ví dụ 9.9 ngoại trừ việc thêm vào một chỉ mục được nạp
chồng
lấy tham số chỉ mục là chuỗi và phương thức findString() tạo ra để lấy chỉ mục
nguyên từ chuỗi.
Phương thức findString() đơn giản là lặp mảng strings cho đến khi nào tìm được chuỗi
có ký
tự đầu tiên trùng với ký tự đầu tiên của chụổi tham số. Nếu tìm thấy thì tr
ả về chỉ mục
của chuỗi, trường hợp ngược lại trả về -1.
Như chúng ta thấy trong hàm Main(), lệnh truy cập chỉ mục thứ hai dùng chuỗi làm
tham số chỉ mục, như đã làm với số nguyên trước:
lbt[“hell”] = “Hi”;
Khi đó nạp chồng chỉ mục sẽ được gọi, sau khi kiểm tra chuỗi hợp lệ tức là không
rỗng, chuỗi này sẽ được truyền vào cho phương thứ
c findString(), kết quả
findString() trả về là một chỉ mục nguyên, số nguyên này sẽ được sử dụng làm chỉ
mục:
return this[ findString(index)];
Ví dụ 9.10 trên tồn tại lỗi khi một chuỗi truyền vào không phù hợp với bất cứ chuỗi
nào trong mảng, khi đó giá trị trả về là –1. Sau đó giá trị này được dùng làm chỉ mục
vào chuỗi mảng strings. Điều này sẽ tạo ra một ngoại lệ
(System.NullReferenceException). Trường hợ
p này xảy ra khi chúng ta bỏ đấu
comment của lệnh:
lbt[“xyzt”] = ”error!”;
Các trường hợp phát sinh lỗi này cần phải được loại bỏ, đây có thể là bài tập cho chúng ta
làm thêm và việc này hết sức cần thiết.
Giao diện tập hợp
Môi trường .NET cung cấp những giao diện chuẩn cho việc liệt kê, so sánh, và tạo
các tập hợp. Một số các giao diện trong số đó được liệt kê trong bảng 9.2 sau:
Giao diện Mục
đích
IEnumerable
Liệt kê thông qua một tập hợp bằng cách sử
dụng
foreach.
ICollection
Thực thi bởi tất cả các tập hợp để cung cấp
phương thức CopyTo() cũng như các thuộc
tính Count,
ISReadOnly, ISSynchronized, và SyncRoot.
IComparer
So sánh giữa hai đối tượng lưu giữ trong tập hợ
p
để
sắp xếp các đối tượng trong tập hợp.
IList Sử dụng bởi những tập hợp mảng được chỉ mục
IDictionary
Dùng trong các tập hợp dựa trên khóa và giá trị
như
Hashta
ble và SortedList.
IDictionaryEnumerator
Cho phép liệt kê dùng câu lệnh foreach qua tập
hợp
hỗ
trợ IDictionary.
Giao diện IEnumerable
Bảng 9.2: Giao diện cho tập hợp.
Chúng ta có thể hỗ trợ cú pháp foreach trong lớp ListBoxTest bằng việc thực
thi giao diện IEnumerator. Giao diện này chỉ có một phương thức duy nhất là
GetEnumerator(), công việc của phương thức là trả về một sự thực thi đặc biệt của
IEnumerator. Do vậy, ngữ nghĩa của lớp Enumerable là nó có thể cung cấp một
Enumerator:
public IEnumerator GetEnumerator()
{
return (IEnumerator) new ListBoxEnumerator(this);
}
Enumerator phải thực thi những phương thức và thuộc tính IEnumerator. Chúng có thể
được thực thi trực tiếp trong lớp chứa (trong trường hợp này là lớp ListBoxTest) hay
bởi một lớp phân biệt khác. Cách tiếp cận thứ hai thường được sử dụng nhiều hơn,
do chúng được đóng gói trong lớp Enumerator hơn là việc phân vào trong các lớp
chứa.
Do lớp Enumerator được xác định cho lớp chứa, vì theo như trên thì lớp
ListBoxEnumerator phải biết nhiều về
lớp ListBoxTest. Nên chúng ta phải tạo cho nó
một sự thực thi riêng chứa bên trong lớp ListBoxTest. Lưu ý rằng phương thức
GetEnumerator truyền đối tượng List- BoxTest hiện thời (this) cho enumerator. Điều
này cho phép enumerator có thể liệt kê được các thành phần trong tập hợp của đối
tượng ListBoxTest. Ở đây lớp thực thi Enumerator là ListBoxEnumerator, đây là một
lớp private được định nghĩa bên trong lớp ListBoxTest. Lớp này thực thi đơn giản
bao gồm một thuộc tính public
, và hai phương thức public là MoveNext(), và
Reset(). Đối tượng ListBoxTest được truyền vào như một đối mục của bộ khởi tạo.
Ở đây nó được gán cho biến thành viên myLBT. Trong hàm khởi tạo này cũng thực
hiện thiết lập giá trị biến thành viên index là -1, chỉ ra rằng chưa bắt đầu thực
hiện việc enumerator đối tượng:
public ListBoxEnumerator(ListBoxTest lbt)
{
this.lbt = lbt;
index = -1;
}
Phương thức MoveNext() gia tăng index và sau đó kiểm tra để đảm bảo rằng việc thực
hiện không vượt quá số phần tử trong tập hợp của đối tượng:
public bool MoveNext()
{
index++;
if (index >= lbt.strings.Length)
return false;
else
return true;
}
Phương thức IEnumerator.Reset() không làm gì cả nhưng thiết lập lại giá trị của index
là -1. Thuộc tính Current trả về đối tượng chuỗi hiện hành. Đó là tất cả những việc cần
làm cho lớp ListBoxTest thực thi một giao diện IEnumerator. Câu lệnh foreach sẽ
được gọi để đem về một enumerator, và sử dụng nó để liệt kê lần lượt qua các thành
phần trong mảng. Sau đây là toàn bộ chương trình minh họa cho việ
c thực thi trên.
Ví dụ 9.11: Tạo lớp ListBox hỗ trợ enumerator.
-----------------------------------------------------------------------------
namespace Programming_CSharp
{
using System;
using System.Collections;
// tạo một control đơn giản
public class ListBoxTest: IEnumerable
{
// lớp thực thi riêng ListBoxEnumerator
private class ListBoxEnumerator : IEnumerator
{
public ListBoxEnumerator(ListBoxTest lbt)
{
this.lbt = lbt;
index = -1;
}
// gia tăng index và đảm bảo giá trị này hợp lệ
public bool MoveNext()
{
index++;
if (index >= lbt.strings.Length)
return false;
else
return true;
}
public void Reset()
{
index = -1;
}
public object Current
{
get
{
}
}
return( lbt[index]);
private ListBoxTest lbt;
private int index;
}
// trả về Enumerator
public IEnumerator GetEnumerator()
{
return (IEnumerator) new ListBoxEnumerator(this);
}
// khởi tạo listbox với chuỗi
public ListBoxTest (params string[] initStr)
{
strings = new String[10];
// copy từ mảng chuỗi tham số
foreach (string s in initStr)
{
strings[ctr++] = s;
}
}
public void Add(string theString)
{
strings[ctr] = theString;
ctr++;
}
// cho phép truy cập giống như mảng
public string this[int index]
{
get