Indexers

นวพล สิงห์ลอ 650710834

C# Indexers

Indexer ช่วยให้เราเข้าถึง instance ของคลาส(class) หรือ struct โดยการใช้ index ซึ่งคล้ายกับ การเข้าถึง element ใน array

การสร้าง C# Indexer

สร้างง่ายๆเหมือนการสร้าง properties ใช้แทนชื่อเป็น this keyword ตามด้วย [ ] index เช่น

public int this[int index] {
    get {
        return val[index];
    }
    set {
        val[index] = value;
    }
}

รายละเอียด

  • public - access modifier เช่น private

  • int - return type ของ indexer เช่น float, string

  • this - ระบุว่านี้คือ indexer ของคลาสนี้

  • int index - เข้าถึงโดยใช้ integer เป็น index เช่น float, string

  • get - method that returns values

  • set - method that assigns values

ตัวอย่าง

using System;
class IndexerCreation {
    // Field
    private string[] val = new string[3]; 
    // สร้าง Indexer
    public string this[int index] {
        get {
            return val[index];
        }
        set {
            val[index] = value;
        }
    }
}
class Main {

    public static void Main() {
        // สร้าง indexer จากคลาสแม่
        IndexerCreation ic = new IndexerCreation();
        // กำหนดค่าผ่าน set
        ic[0] = "C";
        ic[1] = "CPP";
        ic[2] = "CSHARP";
 
        Console.Write("Printing values stored in objects used as arrays\n");
        // เข้าถึงผ่าน get
        Console.WriteLine("First value = {0}", ic[0]);
        Console.WriteLine("Second value = {0}", ic[1]);
        Console.WriteLine("Third value = {0}", ic[2]);
     
    }
}

ตัวอย่างการใช้งานและเปรียบเทียบระหว่าง Indexer กับ Array

Indexer และ Array ใน C# มีความคล้ายคลึงกันตรงที่สามารถเข้าถึงข้อมูลโดยใช้ดัชนี (index) ได้ แต่ทั้งสองก็มีความแตกต่างกันในบางลักษณะการใช้งานและบทบาท

using System;
class Indexer {
    private string[] studentName = new string[10];

    public string this[int index] {
        get {
            // สามารถเพิ่มเงื่อนไข
            if (index == 1)
                throw new InvalidOperationException("Index 1 unable to access");
            return studentName[index];
        }
        set {
            // สามารถเพิ่มเงื่อนไข
            if (index == 1)
                throw new InvalidOperationException("Index 1 unable to access");
            studentName[index] = value;
        }
    }
}
class Main {
    public static void Main() {
        // Indexer
        Indexer indexerStudent  = new Indexer();
        indexerStudent[0] = "Harry";
        indexerStudent[1] = "Ron"; // Index 1 unable to acces
        indexerStudent[2] = "Hermoine";
        Console.WriteLine(indexerStudent[0]); // แสดง Harry
        Console.WriteLine(indexerStudent[1]); // Index 1 unable to access
        Console.WriteLine(indexerStudent[2]); // แสดง Hermoine
        
        // Array
        string[] arrStudent = { "Alice", "Bob", "Charlie" };
        Console.WriteLine(arrStudent[0]); // แสดง Alice
        Console.WriteLine(arrStudent[1]); // แสดง Bob
        Console.WriteLine(arrStudent[2]); // แสดง Charlie
    }
}

เห็นได้ว่า array จะสามารถเข้าถึง/เปลี่ยนแปลง element ได้ทุกตัว แต่ Indexer สามารถเพิ่มเงื่อนไขการเข้าถึง/เปลี่ยนแปลงค่าได้

สรุปความแตกต่าง :

หัวข้อ
Array
Indexer

ด้านการใช้งาน

เก็บข้อมูลหลายๆตัวภายใต้ตัวแปรตัวเดียว

ใช้ใน คลาส หรือ struct เพื่อทำให้วัตถุถูกเข้าถึงได้เหมือนกับอาร์เรย์

ด้านการเข้าถึง

ไม่สามารถควบคุมการเข้าถึงหรือสร้างเงื่อนไขได้

สามารถกำหนดเงื่อนไขในการเข้าถึงข้อมูลได้ผ่านเมธอด get( ) และ set( )

ตัวอย่างการใช้งาน

การเก็บข้อมูลง่ายๆ เช่น ตัวเลข, สตริง หรืออ็อบเจ็กต์

ใช้ในกรณีที่ต้องการให้คลาสหรือคอลเลกชันมีการใช้งานคล้ายอาร์เรย์มากขึ้น


ใน C# เราสามารถใช้งาน Indexer ร่วมกัน Generic Class ได้ (Generic class ช่วยให้เราสามารถกำหนดชนิดข้อมูล ที่จะถูกใช้งานได้ในภายหลัง เมื่อเราสร้างอินสแตนซ์ของคลาสนั้นๆ ทำให้เราสามารถสร้างคลาสที่มีความยืดหยุ่นของชนิดข้อมูลได้ คือ ให้ผู้ใช้กำหนด datatype เอง)

ตัวอย่าง generic indexer

using System;
class EmployeeInfo<T> {
    // สร้าง array ชนิดข้อมูล T
    private T[] employee = new T[50];
    // สร้าง indexer โดยระบุ return type T
    public T this[int index] {
        get {
            return employee[index];
        }
        set {
            employee[index] = value;
        }
    }
}
class Main {
    public static void Main() {
        // ชนิดข้อมูล int
        EmployeeInfo<int> Id = new EmployeeInfo<int>();
        Id[0] = 3;
        Id[1] = 23;
        Id[2] = 10;
        Console.WriteLine("First element in Id object: " + Id[0]);

        // ชนิดข้อมูล string
        EmployeeInfo<string> Name = new EmployeeInfo<string>();
        Name[0] = "Taylor";
        Name[1] = "Selena";
        Name[2] = "Joe";
        Console.WriteLine("First element in Name object: " + Name[0]);
    }
}

Indexer สามารถโอเวอร์โหลดได้ Indexer สามารถประกาศด้วยพารามิเตอร์หลายตัวได้ และแต่ละพารามิเตอร์อาจเป็น data type ที่แตกต่างกัน ไม่จำเป็นที่ index จะต้องเป็นจำนวนเต็ม ใน C# สามารถกำหนด index เป็น data type อื่นๆ ได้ เช่น string

ตัวอย่าง overload indexer

class StringDataStore {
    private string[] strArr = new string[10];

    // int indexer
    public string this[int index] {
        get {
            return strArr[index];
        }
        set {
            strArr[index] = value;
        }
    }

    // string indexer
    public string this[string name] {
        get {
            foreach (string str in strArr) {
                if(str.ToLower() == name.ToLower())        
                    return str;
            }       
            return null;
        }
    }
}
class Main {
    public static void Main(string[] args) {
        StringDataStore strStore = new StringDataStore();

        // เข้าถึงแบบ int index
        strStore[0] = "One";
        strStore[1] = "Two";
        strStore[2] = "Three";
        strStore[3] = "Four";
        
        // เข้าถึงแบบ string index
        Console.WriteLine(strStore["one"]);
        Console.WriteLine(strStore["two"]);
        Console.WriteLine(strStore["Three"]);
        Console.WriteLine(strStore["Four"]);
    }
}

ภาษา Java

ในภาษา Java ไม่มีฟีเจอร์ indexer โดยตรงเหมือนกับภาษา C# แต่สามารถใช้วิธีอื่นให้ทำงานใกล้เคียงกับ indexer ได้ทำให้เราสามารถเข้าถึงสมาชิกของคลาสโดยใช้ index ได้ โดยผ่าน getter และ setter ของ java

ตัวอย่าง Indexer ใน C#

public class CSharpIndxer {
    private int[] numbers = new int[10];

    public int this[int index] {
        get { return numbers[index]; }
        set { numbers[index] = value; }
    }
}

ตัวอย่างการจำลอง indexer ใน Java

public class JavaIndexer {
    private int[] numbers = new int[10];

    public int get(int index) {
        return numbers[index];
    }
    public void set(int index, int value) {
        numbers[index] = value;
    }
}

จากตัวอย่าง เมธอด get() รับค่าพารามิเตอร์ index มีหน้าที่ส่งค่าจากอาเรย์ 'numbers' element ที่ index กลับไป เมธอด set() รับค่าพารามิเตอร์ index และ value มีหน้าที่เปลี่ยนค่าในอาเรย์ 'number' element ที่ index ให้เท่ากับ value

public class Main {
    public static void main(String args[]){
        JavaIndexer in = new JavaIndexer();
        in.set(0, 5);
        int value = in.get(0);
        System.out.println(value); // Output: 5
    }
}

ภาษา C

ในภาษา C ไม่มีฟีเจอร์ indexer เหมือนภาษา C# แต่เราสามารถจำลองการทำงานให้คล้ายกันกับ indexer ได้โดยใช้ฟังก์ชันและ array หรือ struct ที่มีการเข้าถึงข้อมูลผ่านตัวชี้ (pointer) หรืออาร์เรย์แบบธรรมดานั่นเอง

ตัวอย่าง Indexer ใน C#

public class CSharpIndxer {
    private int[] numbers = new int[10];

    public int this[int index] {
        get { return numbers[index]; }
        set { numbers[index] = value; }
    }
}

ตัวอย่างการจำลอง indexer ใน C

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int numbers[10];
} CIndexer;

// ฟังก์ชันสำหรับกำหนดค่าใน index ที่กำหนด
void set(CIndexer* obj, int index, int value) {
    if (index >= 0 && index < 10) {
        obj->numbers[index] = value;
    }
}
// ฟังก์ชันสำหรับดึงค่าจาก index ที่กำหนด
int get(CIndexer* obj, int index) {
    if (index >= 0 && index < 10) {
        return obj->numbers[index];
    }
    return 0; // คืนค่า 0 เมื่อใส่ index ไม่ถูกต้อง
}

void main() {
    CIndexer in;
    set(&in, 0, 5);
    set(&in, 1, 10);

    printf("Value at index 0: %d\n", get(&in, 0)); // Output: 5
    printf("Value at index 1: %d\n", get(&in, 1)); // Output: 10

}

จากตัวอย่างนี้ เราใช้ struct 'CIndexer' ที่มีอาร์เรย์ 'numbers' ขนาด 10 ช่อง จากนั้นใช้ฟังก์ชัน set( ) และ get( ) ในการกำหนดค่าและดึงค่าจากตำแหน่งที่ index ที่เราต้องการ

ภาษา Python

ในภาษา Python ไม่มีฟีเจอร์ indexer แบบที่มีในภาษา C# โดยตรง แต่ ภาษา Python สามารถจำลองการทำงานแบบ indexer ได้ด้วยการใช้เมธอดพิเศษ __getitem__ ( ) และ __setitem__( )

ตัวอย่าง Indexer ใน C#

public class CSharpIndxer {
    private int[] numbers = new int[10];

    public int this[int index] {
        get { return numbers[index]; }
        set { numbers[index] = value; }
    }
}

ตัวอย่างการจำลอง indexer ใน Python

class PythonIndexer:
    def __init__(self):
        self.numbers = [0] * 10  # สร้าง list ขนาด 10 ช่อง

    def __getitem__(self, index):
        return self.numbers[index]

    def __setitem__(self, index, value):
        self.numbers[index] = value

# สร้าง indexer
indexer = PythonIndexer()
indexer[0] = 5  # กำหนดค่าใน index 0
indexer[1] = 10  # กำหนดค่าใน index 1

print(indexer[0])  # Output: 5
print(indexer[1])  # Output: 10

เมธอด __init__ ถูกเรียกเมื่อมีการสร้าง PythonIndexer มีการสร้าง self.numbers ให้เป็น list ขนาด 10 ช่อง

เมธอด __getitem__ ถูกใช้เพื่อดึงค่าจาก self.numbers ตาม index ที่ระบุ

เมธอด __setitem__ ถูกใช้เพื่อกำหนดค่าจาก self.numbers ตาม index ที่ระบุ


References

Wagner, B., van der Arend, M., Mialkin, A., Sherer, T., Schonning, N., Wenzel, M., Warren, G., Kulikov, P., Aymeric, A., Next Turn, Senchyna, J., Hoffman, M., B, M., Latham, L., & tompratt-AQ. (2024, August 23). Indexers. Microsoft Learn. Retrieved fromhttps://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/

amanakmsd. (2023, July 13). C# indexers. GeeksforGeeks. Retrieved from https://www.geeksforgeeks.org/c-sharp-indexers/?ref=shm

C# Indexer with example. (n.d.). Programiz. Retrieved fromhttps://www.programiz.com/csharp-programming/indexer

C# Indexers. (n.d.). TutorialsTeacher. Retrieved from https://www.tutorialsteacher.com/csharp/csharp-indexer

Java Encapsulation. (n.d.). Java get and set. w3schools. Retrieved from https://www.w3schools.com/java/java_encapsulation.asp

Python Software Foundation. (n.d.). Data model (Python 3.13.0): __getitem__, __setitem__. In Python documentation. Retrieved [October 11, 2024], from https://docs.python.org/3/reference/datamodel.html#object.__getitem__

Last updated