• Vui lòng đọc nội qui diễn đàn để tránh bị xóa bài viết
  • Tìm kiếm trước khi đặt câu hỏi

[C# và VB.NET] Giới thiệu về Indexer

Các bài viết hướng dẫn về Visual Basic .NET và C#

Điều hành viên: tungcan5diop, QUANITGROBEST

Hình đại diện của người dùng
Dang Minh Du
Thành viên ưu tú
Thành viên ưu tú
Bài viết: 531
Ngày tham gia: T.Tư 02/04/2008 2:08 pm
Đến từ: RGames Team
Has thanked: 3 time
Been thanked: 17 time
Liên hệ:

[C# và VB.NET] Giới thiệu về Indexer

Gửi bàigửi bởi Dang Minh Du » T.Bảy 09/04/2011 10:58 pm

Tên bài viết: Giới thiệu về Indexer
Tác giả: Đặng Minh Dự
Cấp độ bài viết: Beginer (Yêu cầu: biết OOP (đã biết cách xây dựng lớp (Class) trong C#))
Tóm tắt: Vừa mới học về Indexer trong lớp, thấy cũng khá hay và bổ ích nên viết 1 TUT nhỏ để hướng dẫn lại cho các bạn chưa biết! Sẵn tiện coi như tự ôn tập :D


Kỳ 1: Sơ lược về Indexer:

1. Đặt vấn đề:

Bài toán "Nhân viên" (đơn giản):
Một công ty ABC quản lí nhân viên gồm các thông tin: Mã nhân viên (MaNV), Tên nhân viên (TenNV), Năm sinh (NamSinh), Địa chỉ (DiaChi), Tiền lương (TienLuong). Hãy xây dựng chương trình cho công ty trên đề quản lí nhân viên, các chức năng bao gồm:
- Cho phép thêm nhân viên vào danh sách.
- Cho phép xem thông tin một nhân viên bất kỳ trong danh sách nhân viên.
- Cho phép sắp xếp danh sách nhân viên theo tiền lương tăng dần (hoặc giảm dần).
- ...


Với bài toán trên, để đơn giản và thuận tiện cho quá trình sửa chữa, bảo trì,...; ta nên "đối tượng" hóa các thành phần có thể! Tôi xin đưa ra một giải pháp:
- Xây dựng lớp Nhân viên (CNhanVien)
- Xây dựng lớp danh sách nhân viên (CDanhSachNV)


a. Lớp NhanVien:
  1. class CNhanVien
  2.     {
  3.         //Fields
  4.         string m_strMaNV;
  5.         string m_strTenNV;
  6.         int m_iNamSinh;
  7.         string m_strDiaChi;
  8.         long m_lTienLuong;
  9.  
  10.         //Properties
  11.         public string MANV
  12.         {
  13.             get { return m_strMaNV; }
  14.             set { m_strMaNV = value; }
  15.         }
  16.         public string TENNV
  17.         {
  18.             get { return m_strTenNV; }
  19.             set { m_strTenNV = value; }
  20.         }
  21.         public int NAMSINH
  22.         {
  23.             get { return m_iNamSinh; }
  24.             set { m_iNamSinh = value; }
  25.         }
  26.         public string DIACHI
  27.         {
  28.             get { return m_strDiaChi; }
  29.             set { m_strDiaChi = value; }
  30.         }
  31.         public long TIENLUONG
  32.         {
  33.             get { return m_lTienLuong; }
  34.             set { m_lTienLuong = value; }
  35.         }
  36.  
  37.         //Methods
  38.         public CNhanVien(string MaNV, string TenNV, int NamSinh, string DiaChi, long TienLuong)
  39.         {
  40.             m_strMaNV = MaNV;
  41.             m_strTenNV = TenNV;
  42.             m_iNamSinh = NamSinh;
  43.             m_strDiaChi = DiaChi;
  44.             m_lTienLuong = TienLuong;
  45.         }
  46.     }


b. Lớp CDanhSachNV:
  1.     class CDanhSachNV
  2.     {
  3.         //Fields
  4.         ArrayList m_arrNhanVien;
  5.  
  6.         //Properties
  7.         public ArrayList DANHSACHNHANVIEN
  8.         {
  9.             get { return m_arrNhanVien; }
  10.             set { m_arrNhanVien = value; }
  11.         }
  12.  
  13.         //Methods
  14.         public CDanhSachNV()
  15.         {
  16.             m_arrNhanVien = new ArrayList();
  17.         }
  18.  
  19.         public void ThemNV(CNhanVien nv)
  20.         {
  21.             m_arrNhanVien.Add(nv);
  22.         }
  23.     }


Vấn đề: Giả dụ bây giờ chúng ta muốn thêm 2 nhân viên và sau đó cho xuất ra màn hình 1 trong 2 nhân viên trên:

  1. class Program
  2.     {
  3.         static void Main(string[] args)
  4.         {
  5.             CDanhSachNV dsnv = new CDanhSachNV();
  6.             dsnv.ThemNV(new CNhanVien("01","Nguyen van a", 1991,"tpHCM",3500000)); //Nhap
  7.             dsnv.ThemNV(new CNhanVien("02","Nguyen van b", 1991,"tpHaNoi",3500000));
  8.  
  9.     dsnv.DANHSACHNHANVIEN[0] = new CNhanVien("00a", "Nguyen van a", 1991, "tpHCM", 3500000); //Sua
  10.             CNhanVien nv = (CNhanVien)dsnv.DANHSACHNHANVIEN[1];
  11.  
  12.             Console.WriteLine(nv.TENNV); //Xuat
  13.         }
  14.     }


Khi đó, chúng ta thấy, để truy xuất tới một nhân viên, chúng ta phải thông qua thuộc tính "DANHSACHNHANVIEN"(thực chất là field m_arrDanhSachNV của lớp CDanhSachNV), đó là chưa kể đến nếu dùng ArrayList thì chúng ta còn phải trải qua vài bước trung gian (ép kiểu rồi gán vào biến tạm) trước khi có thể xuất ra được! :-S

Đó mới chỉ là một việc khá đơn giản: "Nhập - Sửa - Xuất", nếu như dữ liệu bài toán của chúng ta phức tạp hơn và các yêu cầu xử lý rắc rối hơn, có lẽ chúng ta phải bỏ ra khá nhiều thời gian để code ;)) ! "Ái chà! Rắc rối quá!" :-?

Không muốn bình thường và phải rối rắm như những ngôn ngữ khác, C# nghĩ ra Indexer - chỉ mục, và chỉ mục này không phải có sẵn, chúng ta sẽ tự định nghĩa cho nó!

Hãy nghĩ đến mọi việc sẽ giảm nhẹ đi như thế nào khi bạn chi cần viết:
  1. dsnv[0] = new CNhanVien(...);
  2. Console.WriteLine(dsnv[0].TENNV);

Tức là ta không cần phải thông qua bất kỳ thuộc tính nào mà vẫn truy xuất được một đối tượng trong mảng đối tượng thông qua chỉ mục hoặc khóa của đối tượng đó!

Tạm kết: C# cung cấp cho chúng ta khái niệm Indexer, cho phép người dùng định nghĩa khả năng truy xuất đến đối tượng trong mảng đối tượng một cách dễ dàng thông qua chỉ mục giống như mảng số hay mảng ký tự (Object[i]) hoặc thông qua khóa (Object[Id]).

Kỳ 2: Xây dựng "Indexer":

1. Khái quát:
Indexer sẽ được định nghĩa trực tiếp trong phần định nghĩa của lớp, có cấu trúc gần tương tự Properties với các phương thức get, set bên trong.
[csharp]public <kiểu trả về> this[int <iIndex>]
{
get
{
//định ghĩa get
}
set
{
//định ghĩa set
}
}
hoặc
public <kiểu trả về> this[<Kiểu> <idString>]
{
get
{
//định ghĩa get
}
set
{
//định ghĩa set
}
}[/csharp]

2. Xây dựng Indexer:
Trở lại với bài toán ở Kỳ 1, thay vì sử dụng chỉ mục đối với thuộc tính của mảng đối tượng để truy xuất tới một đối tượng trong mảng, bây giờ, chúng ta định nghĩa Indexer (định nghĩa trong lớp CDanhSachNV) để đơn giản hóa việc này!
Nhìn chung, chúng ta có 2 cách định (2 loại) Indexer đó là Indexer theo chỉ mục (1, 2, 3, ...) và Indexer theo khóa (id1, id2, id3, ...)

a. Indexer theo chỉ mục:
[csharp]public CNhanVien this[int iIndex]
{
get
{
if (iIndex < 0 || iIndex >= m_arrNhanVien.Count)
{
throw new ArgumentOutOfRangeException();
}
else
{
return (CNhanVien)m_arrNhanVien[iIndex];
}
}

set
{
if (iIndex < 0 || iIndex >= m_arrNhanVien.Count)
{
throw new ArgumentOutOfRangeException();
}
else
{
m_arrNhanVien[iIndex] = value;
}
}
}[/csharp]

Sử dụng:
[csharp]static void Main(string[] args)
{
CDanhSachNV dsnv = new CDanhSachNV();
dsnv.ThemNV(new CNhanVien("01", "Nguyen van a", 1991, "tpHCM", 3500000)); //Nhap
dsnv.ThemNV(new CNhanVien("02", "Nguyen van b", 1991, "tpHaNoi", 3500000));

dsnv[0] = new CNhanVien("00a", "Nguyen van a", 1991, "tpHCM", 3500000); //Sua
Console.WriteLine(dsnv[1].TENNV); //Xuat

}[/csharp]

b. Theo khóa:
[csharp]public CNhanVien this[string strMaNV]
{
get
{
for (int i = 0; i < m_arrNhanVien.Count; i++)
{
CNhanVien nv = (CNhanVien)m_arrNhanVien[i];
if (nv.MANV == strMaNV)
{
return nv;
}
}
return null;
}

set
{
for (int i = 0; i < m_arrNhanVien.Count; i++)
{
CNhanVien nv = (CNhanVien)m_arrNhanVien[i];
if (nv.MANV == strMaNV)
{
m_arrNhanVien[i] = value;
break;
}
}
}
}[/csharp]

Sử dụng:
[csharp]static void Main(string[] args)
{
CDanhSachNV dsnv = new CDanhSachNV();
dsnv.ThemNV(new CNhanVien("01", "Nguyen van a", 1991, "tpHCM", 3500000)); //Them
dsnv.ThemNV(new CNhanVien("02", "Nguyen van b", 1991, "tpHaNoi", 3500000));

dsnv["01"] = new CNhanVien("00a", "Nguyen van c", 1991, "tpHCM", 3500000); //Sua
Console.WriteLine(dsnv["00a"].TENNV); //Xuat

}[/csharp]

*Lưu ý: Đối với việc định nghĩa chỉ mục theo khóa, không nên định nghĩa phương thức set để tránh mâu thuẫn phát sinh trong vấn đề sửa dữ liệu:
[csharp]static void Main(string[] args)
{
CDanhSachNV dsnv = new CDanhSachNV();
dsnv.ThemNV(new CNhanVien("01", "Nguyen van a", 1991, "tpHCM", 3500000)); //Them
dsnv.ThemNV(new CNhanVien("02", "Nguyen van b", 1991, "tpHaNoi", 3500000));

dsnv["01"] = new CNhanVien("00a", "Nguyen van c", 1991, "tpHCM", 3500000); //Sua
Console.WriteLine(dsnv["01"].TENNV); //Xuat //Loi

}[/csharp]

Kết: Nhìn chung Indexer khá dễ nắm bắt, nó lại giúp chúng ta khá nhiều trong việc đơn giản hóa và cụ thể hóa khả năng truy xuất phần tử trong mảng đối tượng!
Vậy là bài viết đã xong, tóm đi tóm lại cũng chỉ có 1 ý ;)) ! Nội dung này mình viết hơi dài, nhưng thực chất lại khá dễ ;) , hy vọng các mới làm quen với lập trình CSharp lại có thêm kiến thức mới bổ ích cho bản thân! Thân chào! :)
Sửa lần cuối bởi Dang Minh Du vào ngày T.Hai 11/04/2011 1:24 pm với 8 lần sửa.



Hình đại diện của người dùng
Dang Minh Du
Thành viên ưu tú
Thành viên ưu tú
Bài viết: 531
Ngày tham gia: T.Tư 02/04/2008 2:08 pm
Đến từ: RGames Team
Has thanked: 3 time
Been thanked: 17 time
Liên hệ:

Re: [C#] Giới thiệu về Indexer

Gửi bàigửi bởi Dang Minh Du » T.Bảy 09/04/2011 10:59 pm

Còn đây là Source Code minh họa để các bạn test tham khảo:
Tập tin đính kèm
XdIndexer.rar
(40.11 KiB) Đã tải 389 lần

Hình đại diện của người dùng
alexanderdna
Guru
Guru
Bài viết: 214
Ngày tham gia: T.Ba 14/07/2009 11:13 am
Đến từ: Sài Gòn
Has thanked: 3 time
Been thanked: 15 time

Re: [C#] Giới thiệu về Indexer

Gửi bàigửi bởi alexanderdna » T.Hai 11/04/2011 9:23 am

Bài viết rất hữu ích. Nếu có thể, mong bạn viết thêm bên Visual Basic .NET nữa cho đủ bộ.
Ngoài lề chút: dùng ArrayList hơi cực khổ, sao không dùng List<CNhanVien>?

Hình đại diện của người dùng
Dang Minh Du
Thành viên ưu tú
Thành viên ưu tú
Bài viết: 531
Ngày tham gia: T.Tư 02/04/2008 2:08 pm
Đến từ: RGames Team
Has thanked: 3 time
Been thanked: 17 time
Liên hệ:

Re: [C#] Giới thiệu về Indexer

Gửi bàigửi bởi Dang Minh Du » T.Hai 11/04/2011 12:34 pm

alexanderdna đã viết:Bài viết rất hữu ích. Nếu có thể, mong bạn viết thêm bên Visual Basic .NET nữa cho đủ bộ.
Ngoài lề chút: dùng ArrayList hơi cực khổ, sao không dùng List<CNhanVien>?

Mình được thầy giới thiệu về ArrayList, tuy nhiên lại k được giới thiệu về List :-/ , mình mới xem qua! Đúng là dùng List sẽ gọn hơn (đỡ phải ép kiểu) :D ! Vậy mà trước giờ k biết! Thanks bạn đã nhắc nhở! :)
p/s: mình sẽ bổ sung VB.NET sau!
Sửa lần cuối bởi Dang Minh Du vào ngày T.Bảy 16/04/2011 7:12 pm với 1 lần sửa.

Hình đại diện của người dùng
Dang Minh Du
Thành viên ưu tú
Thành viên ưu tú
Bài viết: 531
Ngày tham gia: T.Tư 02/04/2008 2:08 pm
Đến từ: RGames Team
Has thanked: 3 time
Been thanked: 17 time
Liên hệ:

Re: [C# và VB.NET] Giới thiệu về Indexer

Gửi bàigửi bởi Dang Minh Du » T.Hai 11/04/2011 1:23 pm

Bonus: Indexer trong VB.NET

Theo yêu cầu của alexanderdna, mình xin bổ sung Indexer trong VB.NET cho "đủ bộ"!

Về tổng quát, Indexer cũng được hỗ trợ trong VB.NET và gần như hoàn toàn giống với C# (chỉ khác về cú pháp)!

Cách định nghĩa Indexer trong VB.NET:
  1. Default Public Property Item(ByVal <iIndex> As Integer) As <Kiểu trả về>
  2.     Get
  3.         'Định nghĩa get
  4.     End Get
  5.     Set(ByVal value As <Kiểu>)
  6.         'Định nghĩa set
  7.     End Set
  8. End Property
  9.  
  10. hoặc
  11.  
  12. Default Public Property Item(ByVal <Id> As <Type>) As <Kiểu trả về>
  13.     Get
  14.         'Định nghĩa get
  15.     End Get
  16.     Set(ByVal value As <Kiểu>)
  17.         'Định nghĩa set
  18.     End Set
  19. End Property


Suy ra với bài toán trên, ta định nghĩa Indexer trong VB.NET như sau:
  1. 'Indexer theo chỉ mục
  2. Default Public Property Item(ByVal iIndex As Integer) As CNhanVien
  3.             Get
  4.                 If iIndex < 0 OrElse iIndex >= m_arrNhanVien.Count Then
  5.                     Throw New ArgumentOutOfRangeException()
  6.                 Else
  7.                     Return m_arrNhanVien(iIndex)
  8.                 End If
  9.             End Get
  10.  
  11.             Set(ByVal value As CNhanVien)
  12.                 If iIndex < 0 OrElse iIndex >= m_arrNhanVien.Count Then
  13.                     Throw New ArgumentOutOfRangeException()
  14.                 Else
  15.                     m_arrNhanVien(iIndex) = value
  16.                 End If
  17.             End Set
  18.         End Property
  19.  
  20. 'Indexer theo khóa
  21.         Default Public Property Item(ByVal strMaNV As String) As CNhanVien
  22.             Get
  23.                 For i As Integer = 0 To m_arrNhanVien.Count - 1
  24.                     Dim nv As CNhanVien = m_arrNhanVien(i)
  25.                     If nv.MANV = strMaNV Then
  26.                         Return nv
  27.                     End If
  28.                 Next
  29.                 Return Nothing
  30.             End Get
  31.  
  32.             Set(ByVal value As CNhanVien)
  33.                 For i As Integer = 0 To m_arrNhanVien.Count - 1
  34.                     Dim nv As CNhanVien = m_arrNhanVien(i)
  35.                     If nv.MANV = strMaNV Then
  36.                         m_arrNhanVien(i) = value
  37.                         Exit For
  38.                     End If
  39.                 Next
  40.             End Set
  41.         End Property



Code Test:
  1.         Sub Main()
  2.             Dim dsnv As New CDanhSachNV()
  3.             dsnv.ThemNV(New CNhanVien("01", "Nguyen van a", 1991, "tpHCM", 3500000))
  4.             'Them
  5.             dsnv.ThemNV(New CNhanVien("02", "Nguyen van b", 1991, "tpHaNoi", 3500000))
  6.  
  7.             dsnv("01") = New CNhanVien("00a", "Nguyen van c", 1991, "tpHCM", 3500000)
  8.             'Sua
  9.             Console.WriteLine(dsnv("00a").TENNV)
  10.             'Xuat
  11.  
  12.         End Sub


Bổ sung code Class CNhanVien và CDanhSachNV:

CNhanVien:
  1.    Class CNhanVien
  2.         'Fields
  3.         Private m_strMaNV As String
  4.         Private m_strTenNV As String
  5.         Private m_iNamSinh As Integer
  6.         Private m_strDiaChi As String
  7.         Private m_lTienLuong As Long
  8.  
  9.         'Properties
  10.         Public Property MANV() As String
  11.             Get
  12.                 Return m_strMaNV
  13.             End Get
  14.             Set(ByVal value As String)
  15.                 m_strMaNV = value
  16.             End Set
  17.         End Property
  18.         Public Property TENNV() As String
  19.             Get
  20.                 Return m_strTenNV
  21.             End Get
  22.             Set(ByVal value As String)
  23.                 m_strTenNV = value
  24.             End Set
  25.         End Property
  26.         Public Property NAMSINH() As Integer
  27.             Get
  28.                 Return m_iNamSinh
  29.             End Get
  30.             Set(ByVal value As Integer)
  31.                 m_iNamSinh = value
  32.             End Set
  33.         End Property
  34.         Public Property DIACHI() As String
  35.             Get
  36.                 Return m_strDiaChi
  37.             End Get
  38.             Set(ByVal value As String)
  39.                 m_strDiaChi = value
  40.             End Set
  41.         End Property
  42.         Public Property TIENLUONG() As Long
  43.             Get
  44.                 Return m_lTienLuong
  45.             End Get
  46.             Set(ByVal value As Long)
  47.                 m_lTienLuong = value
  48.             End Set
  49.         End Property
  50.  
  51.         'Methods
  52.         Public Sub New(ByVal MaNV As String, ByVal TenNV As String, ByVal NamSinh As Integer, ByVal DiaChi As String, ByVal TienLuong As Long)
  53.             m_strMaNV = MaNV
  54.             m_strTenNV = TenNV
  55.             m_iNamSinh = NamSinh
  56.             m_strDiaChi = DiaChi
  57.             m_lTienLuong = TienLuong
  58.         End Sub
  59.     End Class

CDanhSachNV: (Chưa Indexer)
  1.     Class CDanhSachNV
  2.         'Fields
  3.         Private m_arrNhanVien As List(Of CNhanVien)
  4.  
  5.         'Properties
  6.         Public Property DANHSACHNHANVIEN() As List(Of CNhanVien)
  7.             Get
  8.                 Return m_arrNhanVien
  9.             End Get
  10.             Set(ByVal value As List(Of CNhanVien))
  11.                 m_arrNhanVien = value
  12.             End Set
  13.         End Property
  14.  
  15.         'Methods
  16.         Public Sub New()
  17.             m_arrNhanVien = New List(Of CNhanVien)()
  18.         End Sub
  19.  
  20.         Public Sub ThemNV(ByVal nv As CNhanVien)
  21.             m_arrNhanVien.Add(nv)
  22.         End Sub
  23.     End Class

Source code:
VB_Indexer.rar
(54.2 KiB) Đã tải 366 lần

HẾT


p/s: Xin phép đổi tên Topic: [C# và VB.NET]Giới thiệu về Indexer

Hình đại diện của người dùng
alexanderdna
Guru
Guru
Bài viết: 214
Ngày tham gia: T.Ba 14/07/2009 11:13 am
Đến từ: Sài Gòn
Has thanked: 3 time
Been thanked: 15 time

Re: [C# và VB.NET] Giới thiệu về Indexer

Gửi bàigửi bởi alexanderdna » T.Bảy 16/04/2011 12:05 pm

Dang Minh Du đã viết:@Tuy nhiên lưu ý: với trường hợp trên, List tỏ ra ưu thế hơn ArrayList, nhưng ở một vài trường hợp khác, đặc biệt là trường hợp lớp Nhân Viên được nhiều lớp khác kế thừa thì ngược lại ArrayList tỏ ra ưu thế!


Không biết có phải ý bạn là không thể dùng các lớp kế thừa của Nhân Viên trong List<CNhanVien> không?
Nếu vậy thì tôi phải có đôi lời, để cho thông tin được chính xác.

Xin xem mã sau:
  1. class CNhanVien { /*...*/ }
  2. class CNhanVienVanPhong : CNhanVien { /*...*/ }

Và mã sau:
  1. public void Test()
  2. {
  3.     List<CNhanVien> lst = new List<CNhanVien>();
  4.     lst.Add(new CNhanVien());
  5.     lst.Add(new CNhanVienVanPhong());
  6. }


Bạn kiểm tra thử xem. Đó là up-casting.

Hình đại diện của người dùng
Dang Minh Du
Thành viên ưu tú
Thành viên ưu tú
Bài viết: 531
Ngày tham gia: T.Tư 02/04/2008 2:08 pm
Đến từ: RGames Team
Has thanked: 3 time
Been thanked: 17 time
Liên hệ:

Re: [C# và VB.NET] Giới thiệu về Indexer

Gửi bàigửi bởi Dang Minh Du » T.Bảy 16/04/2011 7:11 pm

Thanks bạn! Mình sẽ sửa lại bài viết! Ý mình nói đúng ra là ArrayList chứa phần tử là Object (Đối tượng, lớp cha của tất cả các lớp), còn đối với List là phần tử có 1 kiểu cụ thể!

Hình đại diện của người dùng
TheDark
Guru
Guru
Bài viết: 188
Ngày tham gia: T.Năm 04/11/2010 3:56 pm
Đến từ: Mang Thít - Vĩnh Long
Has thanked: 6 time
Been thanked: 33 time

Re: [C# và VB.NET] Giới thiệu về Indexer

Gửi bàigửi bởi TheDark » T.Bảy 16/04/2011 9:11 pm

Mình có chút ý kiến nhỏ. Nên sửa
Lớp CDanhSachNV thành:

  1. class CDanhSachNV: List <CNhanVien >
  2.     {
  3.         //Methods
  4.         public CDanhSachNV()
  5.         {
  6.             m_arrNhanVien = new List <CNhanVien >;
  7.         }
  8.  
  9.         public void ThemNV(CNhanVien nv)
  10.         {
  11.             CDanhSachNV.Add(nv);
  12.         }
  13.         public void XoaNV(CNhanVien nv)
  14.         {
  15.             CDanhSachNV.Remove(nv);
  16.         }
  17.     }


Quay về “[.NET] Bài viết hướng dẫn”

Đang trực tuyến

Đang xem chuyên mục này: Không có thành viên nào trực tuyến.2 khách