Sobes.tech
Junior

Cosa sono gli indici in C#? Quali tipi di indici esistono e li hai usati in pratica?

sobes.tech AI

Risposta dell'AI

Gli indicizzatori in C# consentono di accedere a un'istanza di una classe o struttura come se fosse un array, utilizzando la sintassi []. Non sono statici e sovraccaricano l'operatore [].

Indicizzatori

Gli indicizzatori permettono di definire la logica di accesso agli elementi di una collezione o struttura dati all’interno di una classe.

public class MyCollection
{
    private string[] data = new string[10];

    // Indicizzatore che permette di ottenere o impostare un elemento tramite indice
    public string this[int index]
    {
        get
        {
            // Controllo dei limiti
            if (index >= 0 && index < data.Length)
            {
                return data[index];
            }
            else
            {
                throw new IndexOutOfRangeException();
            }
        }
        set
        {
            // Controllo dei limiti
            if (index >= 0 && index < data.Length)
            {
                data[index] = value;
            }
            else
            {
                throw new IndexOutOfRangeException();
            }
        }
    }
}

Tipi di parametri degli indicizzatori

Gli indicizzatori possono accettare qualsiasi numero di parametri di qualsiasi tipo, non limitandosi ai soli tipi interi.

public class DictionaryLike
{
    private Dictionary<string, string> _dictionary = new Dictionary<string, string>();

    // Indicizzatore con parametro di tipo string
    public string this[string key]
    {
        get
        {
            if (_dictionary.ContainsKey(key))
            {
                return _dictionary[key];
            }
            else
            {
                return null; // O lanciare un'eccezione
            }
        }
        set
        {
            _dictionary[key] = value;
        }
    }
}

Sovraccarico degli indicizzatori

È possibile creare indicizzatori sovraccaricati con firme diverse (insieme e tipi di parametri).

public class Matrix
{
    private int[,] data;

    public Matrix(int rows, int cols)
    {
        data = new int[rows, cols];
    }

    // Indicizzatore con due parametri interi
    public int this[int row, int col]
    {
        get
        {
            // Controllo dei limiti
            if (row >= 0 && row < data.GetLength(0) && col >= 0 && col < data.GetLength(1))
            {
                return data[row, col];
            }
            else
            {
                throw new IndexOutOfRangeException();
            }
        }
        set
        {
            // Controllo dei limiti
            if (row >= 0 && row < data.GetLength(0) && col >= 0 && col < data.GetLength(1))
            {
                data[row, col] = value;
            }
            else
            {
                throw new IndexOutOfRangeException();
            }
        }
    }
}

Indici di intervallo (Ranges & Indices)

In C# 8.0 sono stati introdotti i nuovi tipi System.Index e System.Range, che consentono di usare la sintassi per accedere agli elementi dalla fine della collezione (^) e per ottenere sotto-intervalli (..). Questi concetti sono spesso chiamati "indici", ma sono diversi dai classici indicizzatori.

using System;

public class ArrayExample
{
    public static void Main(string[] args)
    {
        string[] words = { "the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog" };

        // Uso di System.Index per l'accesso dalla fine
        Index last = ^1; // Indice dell'ultimo elemento
        Console.WriteLine(words[last]); // dog

        // Uso di System.Range per ottenere un sotto-intervallo
        Range middle = 1..4; // Elementi dall'indice 1 fino (ma non incluso) all'indice 4
        string[] subset = words[middle]; // {"quick", "brown", "fox"}

        // Range con uso di System.Index
        Range fromEnd = ^3..; // dal terzo dall'end fino alla fine
        string[] suffix = words[fromEnd]; // {"the", "lazy", "dog"}
    }
}

Applicazione pratica

Ho utilizzato attivamente gli indicizzatori creando le mie classi di collezioni o wrapper su collezioni esistenti per fornire un accesso più intuitivo ai dati. Per esempio:

  • Sviluppo di classi che rappresentano matrici o dati multidimensionali, dove l'accesso tramite coordinate matrix[row, col] ha senso.
  • Creazione di wrapper su Dictionary<> o altre collezioni, dove l'accesso tramite chiave tramite l'indicizzatore migliorava la leggibilità del codice.
  • In collezioni semplici, dove era necessario un accesso sintattico comodo, simile a un array.

Gli indici di intervallo (System.Index e System.Range) li ho usati per un accesso più conciso a parti di array o liste, il che è particolarmente utile quando si lavora con sottostringhe o dati parziali di una collezione.