Indexer trong C#

Indexer (bộ lập chỉ mục) là một loại thuộc tính đặc biệt cho phép một lớp hoặc struct được truy cập như một mảng.

Một bộ lập chỉ mục có thể được định nghĩa giống như thuộc tính với từ khóa this và dấu ngoặc vuông [].

Cú pháp

Một bộ lập chỉ mục một chiều có cú pháp sau:

element-type this[int index] 
{
   // The get accessor.
   get 
   {
      // return the value specified by index
   }
   
   // The set accessor.
   set 
   {
      // set the value specified by index
   }
}

Sử dụng bộ lập chỉ mục

Khai báo một bộ lập chỉ mục ở một mức độ nào đó tương tự như một thuộc tính. Bạn sử dụng các accessor là getset định nghĩa một bộ lập chỉ mục.

Tuy nhiên, các thuộc tính trả về hoặc gán giá trị cho một thành viên dữ liệu cụ thể, trong khi đó bộ lập chỉ mục trả về hoặc gán một giá trị cụ thể từ đối tượng.

Nói cách khác, nó chia dữ liệu của thể hiện đối tượng thành các phần nhỏ hơn và lập chỉ mục cho từng phần, lấy hoặc gán giá trị cho từng phần này.

Định nghĩa một thuộc tính phải có tên thuộc tính. Bộ lập chỉ mục không được định nghĩa bằng tên, nhưng nó sử dụng từ khóa this, dùng để chỉ thể hiện đối tượng hiện tại.

Ví dụ sau định nghĩa một bộ lập chỉ mục trong lớp.

using System;

namespace IndexerApplication 
{   
   class IndexedNames 
   {
      private string[] namelist = new string[size];
      public static int size = 10;
      
      public IndexedNames() 
      {
         for (int i = 0; i < size; i++)
         {
            namelist[i] = "N. A.";
         }
      }
      
      public string this[int index] 
      {
         get 
         {
            string tmp;
         
            if(index >= 0 && index <= size-1) 
            {
               tmp = namelist[index];
            } 
            else 
            {
               tmp = "";
            }
            
            return tmp;
         }
         set 
         {
            if( index >= 0 && index <= size-1 ) 
            {
               namelist[index] = value;
            }
         }
      }
      
      static void Main(string[] args) 
      {
         IndexedNames names = new IndexedNames();
         names[0] = "Zara";
         names[1] = "Riz";
         names[2] = "Nuha";
         names[3] = "Asif";
         names[4] = "Davinder";
         names[5] = "Sunil";
         names[6] = "Rubic";
         
         for (int i = 0; i < IndexedNames.size; i++) 
         {
            Console.WriteLine(names[i]);
         }
         Console.ReadKey();
      }
   }
}

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

Zara
Riz
Nuha
Asif
Davinder
Sunil
Rubic
N. A.
N. A.
N. A.

Lớp IndexedNames định nghĩa một bộ lập chỉ mục cho mảng riêng của nó là namelist. Vì vậy, bây giờ, bạn có thể sử dụng IndexedNames giống như một mảng để thêm và truy xuất các giá trị chuỗi từ mảng namelist.

Bạn có thể sử dụng cú pháp biểu thức thân để get và set từ C # 7 trở đi như sau:

class StringDataStore
{
    private string[] strArr = new string[10]; // internal data storage

    public string this[int index]
    {
        get => strArr[index];

        set => strArr[index] = value;
    }
}

Bộ lập chỉ mục chung (generic indexer)

Bộ lập chỉ mục cũng có thể chung chung. Lớp chung (generic class) sau đây trình bày về bộ lập chỉ mục chung.

using System;

class DataStore<T>
{
	private T[] store;
	public DataStore()
	{
		store = new T[10];
	}

	public DataStore(int length)
	{
		store = new T[length];
	}

	public T this[int index]
	{
		get
		{
			if (index < 0 && index >= store.Length)
            {
				throw new IndexOutOfRangeException("Index out of range");
            }
			return store[index];
		}
		set
		{
			if (index < 0 || index >= store.Length)
            {
				throw new IndexOutOfRangeException("Index out of range");
			}
            store[index] = value;
		}
	}

	public int Length
	{
		get
		{
			return store.Length;
		}
	}
}

public class Program
{
	public static void Main()
	{
		DataStore<int> grades = new DataStore<int>();
		grades[0] = 100;
		grades[1] = 25;
		grades[2] = 34;
		grades[3] = 42;
		grades[4] = 12;
		grades[5] = 18;
		grades[6] = 2;
		grades[7] = 95;
		grades[8] = 75;
		grades[9] = 53;
		
		for (int i = 0; i < grades.Length; i++)
        {
			Console.WriteLine(grades[i]);
        }
		
		DataStore<string> names = new DataStore<string>(5);
		names[0] = "Steve";
		names[1] = "Bill";
		names[2] = "James";
		names[3] = "Ram";
		names[4] = "Andy";
		
		for (int i = 0; i < names.Length; i++)
        {
			Console.WriteLine(names[i]);
        }
	}
}

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

100
25
34
42
12
18
2
95
75
53
Steve
Bill
James
Ram
Andy

Bộ lập chỉ mục chung ở trên có thể được sử dụng với bất kỳ kiểu dữ liệu nào. Ví dụ sau đây cho thấy việc sử dụng bộ chỉ mục chung.

Nạp chồng bộ lập chỉ mục

Bạn có thể nạp chồng với các loại dữ liệu khác nhau cho chỉ mục. Ví dụ sau đây nạp chồng một bộ lập chỉ mục với chỉ mục kiểu int cũng như chỉ mục kiểu chuỗi.

class StringDataStore
{
    private string[] strArr = new string[10]; // internal data storage

    // int type indexer
    public string this[int index]
    {
        get
        {
            if (index < 0 &&  index >= strArr.Length)
            {
                throw new IndexOutOfRangeException("Index out of range");
			}
            return strArr[index];
        }
        set
        {
            if (index < 0 &&  index >= strArr.Length)
            {
                throw new IndexOutOfRangeException("Index out of range");
			}
            strArr[index] = value;
        }
    }

    // string type indexer
    public string this[string name]
    {
        get
        {
            foreach (string str in strArr)
            {
                if(str.ToLower() == name.ToLower())
                {
                    return str;
                }
            }                    
            return null;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        StringDataStore strStore = new StringDataStore();

        strStore[0] = "One";
        strStore[1] = "Two";
        strStore[2] = "Three";
        strStore[3] = "Four";
        
        Console.WriteLine(strStore["one"]);
        Console.WriteLine(strStore["two"]);
        Console.WriteLine(strStore["Three"]);
        Console.WriteLine(strStore["Four"]);
    }
}

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

One
Two
Three
Four

Tips: Indexer không cho phép tham số ref và out.


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#.