Sobes.tech
Junior

O que são índices em C#? Quais tipos de índices existem e você os utilizou na prática?

sobes.tech IA

Resposta da IA

Os indexadores em C# permitem aceder a uma instância de uma classe ou estrutura como se fosse uma matriz, usando a sintaxe []. Eles não são estáticos e sobrecarregam o operador [].

Indexadores

Os indexadores permitem definir a lógica de acesso aos elementos de uma coleção ou estrutura de dados dentro de uma classe.

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

    // Indexador que permite obter ou definir um elemento por índice
    public string this[int index]
    {
        get
        {
            // Verificação de limites
            if (index >= 0 && index < data.Length)
            {
                return data[index];
            }
            else
            {
                throw new IndexOutOfRangeException();
            }
        }
        set
        {
            // Verificação de limites
            if (index >= 0 && index < data.Length)
            {
                data[index] = value;
            }
            else
            {
                throw new IndexOutOfRangeException();
            }
        }
    }
}

Tipos de parâmetros de indexadores

Os indexadores podem aceitar qualquer número de parâmetros de qualquer tipo, não se limitando apenas a tipos inteiros.

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

    // Indexador com parâmetro do tipo string
    public string this[string key]
    {
        get
        {
            if (_dictionary.ContainsKey(key))
            {
                return _dictionary[key];
            }
            else
            {
                return null; // Ou lançar exceção
            }
        }
        set
        {
            _dictionary[key] = value;
        }
    }
}

Sobrecarga de indexadores

É possível criar indexadores sobrecarregados com diferentes assinaturas (conjunto e tipos de parâmetros).

public class Matrix
{
    private int[,] data;

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

    // Indexador com dois parâmetros inteiros
    public int this[int row, int col]
    {
        get
        {
            // Verificação de limites
            if (row >= 0 && row < data.GetLength(0) && col >= 0 && col < data.GetLength(1))
            {
                return data[row, col];
            }
            else
            {
                throw new IndexOutOfRangeException();
            }
        }
        set
        {
            // Verificação de limites
            if (row >= 0 && row < data.GetLength(0) && col >= 0 && col < data.GetLength(1))
            {
                data[row, col] = value;
            }
            else
            {
                throw new IndexOutOfRangeException();
            }
        }
    }
}

Índices de intervalo (Ranges & Indices)

No C# 8.0 foram introduzidos os novos tipos System.Index e System.Range, que permitem usar a sintaxe para aceder a elementos a partir do final da coleção (^) e para obter subintervalos (..). Estes conceitos são frequentemente chamados de "índices", mas diferem dos indexadores clássicos.

using System;

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

        // Uso de System.Index para aceder a partir do final
        Index last = ^1; // Índice do último elemento
        Console.WriteLine(words[last]); // dog

        // Uso de System.Range para obter um subintervalo
        Range middle = 1..4; // Elementos do índice 1 até (mas não incluindo) o índice 4
        string[] subset = words[middle]; // {"quick", "brown", "fox"}

        // Range usando System.Index
        Range fromEnd = ^3..; // do terceiro desde o final até ao final
        string[] suffix = words[fromEnd]; // {"the", "lazy", "dog"}
    }
}

Aplicação prática

Utilizei ativamente os indexadores ao criar as minhas próprias classes de coleções ou envoltórios sobre coleções existentes para fornecer um acesso mais intuitivo aos dados. Por exemplo:

  • Desenvolvimento de classes que representam matrizes ou dados multidimensionais, onde o acesso por coordenadas matrix[row, col] fazia sentido.
  • Criação de envoltórios sobre Dictionary<> ou outras coleções, onde o acesso por chave através do indexador melhorava a legibilidade do código.
  • Em coleções simples, onde era necessária uma sintaxe de acesso conveniente, semelhante a um array.

Os índices de intervalo (System.Index e System.Range) foram utilizados para um acesso mais conciso a partes de arrays ou listas, o que é especialmente útil ao trabalhar com subcadeias ou dados parciais de uma coleção.