GT C Sharp cơ bản – Bài 19 : Chương 18: Chỉ mục
Chương 18: Chỉ mục
Tác giả: Sưu tầm
Khái quát
Đôi khi ta thấy có thể lập chỉ mục một đối tượng như thể nó là một mảng. Điều này có thể được thực hiện bằng cách tạo một chỉ mục cho một đối tượng, mà nó có thể được xem như một mảng đúng cách. Khi một thuộc tính là một trường nhưng có các accessor để thực hiện các thao tác nhận và thiết đặt, thì một chỉ mục là một mảng, nhưng có các accessor để thực hiện các thao tác chỉ mục cho mảng.
Lập chỉ mục cho một chỉ mục kiểu nguyên
Một lớp chứa một cơ sở dữ liệu row có thể cài đặt một chỉ mục để truy xuất các column trong row:
using System;
using System.Collections;
class DataValue {
public DataValue(string name, object data) {
this.name = name;
this.data = data;
}
public string Name {
get {
return(name);
}
set {
name = value;
}
}
public object Data {
get {
return(data);
}
set {
data = value;
}
}
string name;
object data;
}
class DataRow {
public DataRow() {
row = new ArrayList();
}
public void Load() {
/* load code here */
row.Add(new DataValue(“Id”, 5551212));
row.Add(new DataValue(“Name”, “Fred”));
row.Add(new DataValue(“Salary”, 2355.23m));
}
public object this[int column] {
get {
return(row);
}
set {
row = value;
}
}
ArrayList row;
}
class Test {
public static void
DataRow row = new DataRow();
row.Load();
DataValue val = (DataValue) row[0];
Console.WriteLine(“Column 0: {0}”, val.Data);
val.Data = 12; // set the ID
}
}
Lớp DataRow có các hàm để lấy một row của dữ liệu, các hàm để lưu dữ liệu, và một hàm chỉ mục cung cấp sự truy xuất dữ liệu. Trong một lớp thực sự, hàm Load() sẽ lấy dữ liệu từ một cơ sở dữ liệu.
Hàm chỉ mục được viết giống như cách viết một thuộc tính, ngoại trừ việc nó đòi hỏi một tham số chỉ mục. Chỉ mục được khai báo bằng cách sử dụng từ khoá this vì nó không có tên.
Một lớp có thể có nhiều chỉ mục. Đối với lớp DataRow, nó có thể hữu ích khi cho phép sử dụng tên của column cho việc chỉ mục:
using System;
using System.Collections;
class DataValue {
public DataValue(string name, object data) {
this.name = name;
this.data = data;
}
public string Name {
get {
return(name);
}
set {
name = value;
}
}
public object Data {
get {
return(data);
}
set {
data = value;
}
}
string name;
object data;
}
class DataRow {
public DataRow() {
row = new ArrayList();
}
public void Load() {
/* load code here */
row.Add(new DataValue(“Id”, 5551212));
row.Add(new DataValue(“Name”, “Fred”));
row.Add(new DataValue(“Salary”, 2355.23m));
}
public object this[int column] {
get {
return(row);
}
set {
row = value;
}
}
int FindColumn(string name) {
for (int index = 0; index < row.Count; index++) {
DataValue dataValue = (DataValue) row[index];
if (dataValue.Name == name)
return(index);
}
return(-1);
}
public object this[string name] {
get {
return this[FindColumn(name)];
}
set {
this[FindColumn(name)] = value;
}
}
ArrayList row;
}
class Test {
public static void
DataRow row = new DataRow();
row.Load();
DataValue val = (DataValue) row[“Id”];
Console.WriteLine(“Id: {0}”, val.Data);
Console.WriteLine(“Salary: {0}”, ((DataValue) row[“Salary”]).Data);
((DataValue)row[“Name”]).Data = “Barney”; // set the name
Console.WriteLine(“Name: {0}”, ((DataValue) row[“Name”]).Data);
}
}
Chỉ mục có tham số kiểu chuỗi sử dụng hàm FindColumn() để tìm một chỉ mục của tên, và sau đó sử dụng chỉ mục có tham số kiểu int để thực hiện chính xác.
Các chỉ mục có thể có nhiều hơn một tham số, để mô tả một mảng đa chiều ảo.
Chỉ mục và foreach
Nếu một đối tượng có thể được xem như một mảng, thường là tiện lợi để lặp qua nó bằng cách sử dụng câu lệnh foreach. Để có thể sử dụng foreach, và các cấu trúc tương tự trong các ngôn ngữ .NET khác, giao diện Ienumerable phải được cài đặt bởi đối tượng. Giao diện này có một thành phần đơn lẻ GetEnumerator(), nó trả ra một tham chiếu đến một giao diện Ienumerator, mà nó có các hàm thành phần được sử dụng để thực hiện sự liệt kê.
Giao diện IEnumerator có thể được cài đặt trực tiếp bằng lớp chứa, hoặc có thể được cài đặt bằng một lớp private. Việc cài đặt private là được ưa chuộng và nó đơn giản hoá một lớp sưu tập.
Ví dụ sau mở rộng ví dụ trước để sử dụng foreach:
using System;
using System.Collections;
class DataValue {
public DataValue(string name, object data) {
this.name = name;
this.data = data;
}
public string Name {
get {
return(name);
}
set {
name = value;
}
}
public object Data {
get {
return(data);
}
set {
data = value;
}
}
string name;
object data;
}
class DataRow: IEnumerable {
class DataRowEnumerator: IEnumerator {
public DataRowEnumerator(DataRow dataRow) {
this.dataRow = dataRow;
index = -1;
}
public bool MoveNext() {
index++;
if (index >= dataRow.row.Count)
return(false);
else
return(true);
}
public void Reset() {
index = -1;
}
public object Current {
get {
return(dataRow.row[index]);
}
}
DataRow dataRow;
int index;
}
public DataRow() {
row = new ArrayList();
}
public void Load() {
/* load code here */
row.Add(new DataValue(“Id”, 5551212));
row.Add(new DataValue(“Name”, “Fred”));
row.Add(new DataValue(“Salary”, 2355.23m));
}
public object this[int column] {
get {
return(row);
}
set {
row = value;
}
}
int FindColumn(string name) {
for (int index = 0; index < row.Count; index++) {
DataValue dataValue = (DataValue) row[index];
if (dataValue.Name == name)
return(index);
}
return(-1);
}
public object this[string name] {
get {
return this[FindColumn(name)];
}
set {
this[FindColumn(name)] = value;
}
}
public IEnumerator GetEnumerator() {
return((IEnumerator) new DataRowEnumerator(this));
}
ArrayList row;
}
class Test {
public static void
DataRow row = new DataRow();
row.Load();
foreach (DataValue dataValue in row) {
Console.WriteLine(“{0}: {1}”, dataValue.Name, dataValue.Data);
}
}
}
Vòng lặp foreach trong
IEnumerator enumerator = row.GetEnumerator();
while (enumerator.GetNext()) {
DataValue dataValue = (DataValue) enumerator.Current;
Console.WriteLine(“{0}: {1}”, dataValue.Name, dataValue.Data)
}
Những nguyên tắc thiết kế
Chỉ mục nên được dùng chỉ trong những tình huống mà sự trừu tượng có ý nghĩa. Điều này thường phụ thuộc vào liệu đối tượng là một vật chứa cho một số đối tượng khác hay không.
Chỉ mục nên có cả phương pháp nhận và thiết đặt, như các mảng là các đối tượng đọc/viết. Nếu một chỉ mục chỉ có phương pháp nhận, nên xem xét để đổi nó thành một phương thức.