Sobes.tech
Junior

¿Qué son los índices en C#? ¿Qué tipos de índices existen y los ha utilizado en la práctica?

sobes.tech AI

Respuesta de la IA

Los indexadores en C# permiten acceder a una instancia de una clase o estructura como si fuera un array, usando la sintaxis []. No son estáticos y sobrecargan el operador [].

Indexadores

Los indexadores permiten definir la lógica de acceso a los elementos de una colección o estructura de datos dentro de una clase.

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

    // Indexador que permite obtener o establecer un elemento por índice
    public string this[int index]
    {
        get
        {
            // Verificación de límites
            if (index >= 0 && index < data.Length)
            {
                return data[index];
            }
            else
            {
                throw new IndexOutOfRangeException();
            }
        }
        set
        {
            // Verificación de límites
            if (index >= 0 && index < data.Length)
            {
                data[index] = value;
            }
            else
            {
                throw new IndexOutOfRangeException();
            }
        }
    }
}

Tipos de parámetros de indexadores

Los indexadores pueden aceptar cualquier cantidad de parámetros de cualquier tipo, no limitándose solo a tipos enteros.

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

    // Indexador con parámetro de tipo string
    public string this[string key]
    {
        get
        {
            if (_dictionary.ContainsKey(key))
            {
                return _dictionary[key];
            }
            else
            {
                return null; // O lanzar una excepción
            }
        }
        set
        {
            _dictionary[key] = value;
        }
    }
}

Sobrecarga de indexadores

Se pueden crear indexadores sobrecargados con diferentes firmas (conjunto y tipos de parámetros).

public class Matrix
{
    private int[,] data;

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

    // Indexador con dos parámetros enteros
    public int this[int row, int col]
    {
        get
        {
            // Verificación de límites
            if (row >= 0 && row < data.GetLength(0) && col >= 0 && col < data.GetLength(1))
            {
                return data[row, col];
            }
            else
            {
                throw new IndexOutOfRangeException();
            }
        }
        set
        {
            // Verificación de límites
            if (row >= 0 && row < data.GetLength(0) && col >= 0 && col < data.GetLength(1))
            {
                data[row, col] = value;
            }
            else
            {
                throw new IndexOutOfRangeException();
            }
        }
    }
}

Índices de rango (Ranges & Indices)

En C# 8.0 se introdujeron los nuevos tipos System.Index y System.Range, que permiten usar la sintaxis para acceder a elementos desde el final de la colección (^) y para obtener subrangos (..). Estos conceptos a menudo se llaman "índices", pero difieren de los indexadores clásicos.

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 acceder desde el final
        Index last = ^1; // Índice del último elemento
        Console.WriteLine(words[last]); // dog

        // Uso de System.Range para obtener un subrango
        Range middle = 1..4; // Elementos desde el índice 1 hasta (pero no incluyendo) el índice 4
        string[] subset = words[middle]; // {"quick", "brown", "fox"}

        // Rango usando System.Index
        Range fromEnd = ^3..; // desde el tercero desde el final hasta el final
        string[] suffix = words[fromEnd]; // {"the", "lazy", "dog"}
    }
}

Aplicación práctica

He utilizado activamente los indexadores al crear mis propias clases de colecciones o envoltorios sobre colecciones existentes para proporcionar un acceso más intuitivo a los datos. Por ejemplo:

  • Desarrollo de clases que representan matrices o datos multidimensionales, donde el acceso por coordenadas matrix[row, col] tiene sentido.
  • Creación de envoltorios sobre Dictionary<> u otras colecciones, donde el acceso por clave a través del indexador mejora la legibilidad del código.
  • En colecciones simples, donde se requiere una sintaxis conveniente de acceso, similar a un array.

Los índices de rango (System.Index y System.Range) los he usado para acceder de manera más concisa a partes de arrays o listas, lo cual es especialmente útil al trabajar con subcadenas o datos parciales de una colección.