CodeGym /Cursos /C# SELF /Colecciones: OrderedDictio...

Colecciones: OrderedDictionary y ReadOnlySet

C# SELF
Nivel 34 , Lección 1
Disponible

1. Colección OrderedDictionary

En .NET siempre se ha valorado una biblioteca estándar rica, pero en la vida de un programador a veces había que hacer compromisos: quieres un diccionario que recuerde el orden de inserción de los elementos, o necesitas un conjunto inmutable de valores únicos. Antes de .NET 9, había que usar librerías de terceros o inventar tus propios apaños (alguien incluso abría GitHub y copiaba OrderedDictionary de ahí — shhh, no se lo contaremos a nadie).

Con la llegada de .NET 9 aparecieron nuevas colecciones genéricas — ¡ahora puedes olvidarte de los parches! Vamos a ver en detalle las dos más útiles: OrderedDictionary<TKey, TValue> y ReadOnlySet<T>.

1. ¿Qué es OrderedDictionary?

OrderedDictionary es un híbrido entre diccionario y lista. Guarda pares "clave-valor", como un Dictionary<TKey, TValue> normal, pero garantiza que el orden de los elementos corresponde al orden en que se añadieron. Esto es especialmente importante para tareas donde necesitas recorrer los elementos en el mismo orden en que el usuario los introdujo, o cuando el orden afecta a la lógica de negocio: impresión de informes, serialización de datos, generación de configuraciones.

Analogía

Si un diccionario normal es como un armario con un montón de compartimentos donde puedes meter y sacar cosas rápido sin pensar en el orden, OrderedDictionary es como un armario ordenado con cajones deslizantes. Todo está en orden y siempre sabes qué pusiste primero y qué después.

2. Diferencia principal con Dictionary

  • Dictionary: el orden de los elementos no está garantizado (aunque parezca que siempre sale igual — no te fíes, ¡es una ilusión!).
  • OrderedDictionary: los elementos se guardan exactamente en el orden en que los añadiste.

3. Sintaxis y métodos principales

Aquí tienes un ejemplo básico de uso:


using System.Collections.Generic;

var od = new OrderedDictionary<string, int>();
od.Add("Iván", 5);
od.Add("Svetlana", 8);
od.Add("Alex", 3);

// Recorrido en orden de inserción:
foreach (var pair in od)
{
    Console.WriteLine($"{pair.Key}: {pair.Value}");
}

Salida:

Iván: 5
Svetlana: 8
Alex: 3

Si pruebas el mismo ejemplo con un diccionario normal, el orden muchas veces será diferente. Pero con OrderedDictionary — siempre será exactamente como lo añadiste.

OrderedDictionary implementa las mismas interfaces que un diccionario normal:

  • IDictionary<TKey, TValue>
  • IReadOnlyDictionary<TKey, TValue>
  • IEnumerable<KeyValuePair<TKey, TValue>>

4. Acceso por índice y por clave

Punto especial: OrderedDictionary tiene indexador tanto por clave como por índice de posición.


// Por nombre (clave):
int svetlanaScore = od["Svetlana"]; // 8

// Por índice:
var firstEntry = od.ElementAt(0); // KeyValuePair<string, int>("Iván", 5)

5. Actualización y eliminación

Si añades un nuevo elemento con una clave existente, lanza una excepción. Si quieres reemplazar el valor — usa el indexador:

od["Iván"] = 10; // Cambia el existente, el orden no cambia

Puedes eliminar tanto por clave como por índice:


od.Remove("Svetlana");
od.RemoveAt(0);      // elimina "Iván"

6. Visualización de la estructura


flowchart LR
    A("0: Iván - 5")
    B("1: Svetlana - 8")
    C("2: Alex - 3")
    A --> B --> C
Cada nodo es un par clave-valor, y las flechas muestran el orden de inserción.

7. Trampas y errores

Muchos desarrolladores intentan usar Dictionary<TKey, TValue> y esperan que el orden se mantenga — ¡pero es una trampa! Incluso si con algunos datos el orden se mantiene, la próxima vez puede cambiar (sobre todo si cambias de versión de .NET o de plataforma).

En OrderedDictionary, por guardar el orden, algunas operaciones (insertar, eliminar en medio) son un poco más lentas que en un diccionario normal, pero para la mayoría de los casos las ventajas compensan.

Si necesitas buscar a menudo por índice — esto es justo para OrderedDictionary, pero si solo te importa la búsqueda rápida por clave y el orden te da igual — usa un diccionario normal.

8. Ejemplo práctico para una app

Supón que en nuestra app de gestión de empleados y departamentos ahora necesitamos un informe donde los empleados se muestran en el orden en que fueron añadidos:


var employeeScores = new OrderedDictionary<string, int>();
employeeScores.Add("Petr", 100);
employeeScores.Add("Anna", 150);
employeeScores.Add("Victoria", 80);

// Ahora el informe siempre en el orden correcto:
foreach (var pair in employeeScores)
{
    Console.WriteLine($"{pair.Key}: {pair.Value} puntos");
}

2. Colección ReadOnlySet<T>

1. ¿Qué es ReadOnlySet?

ReadOnlySet<T> es un conjunto inmutable (immutable) de valores únicos. Antes, para crear un "set" solo de lectura, había que devolver una copia con .ToHashSet() o crear tu propio wrapper. Ahora tienes una colección a la que no puedes añadir ni quitar elementos después de crearla. Esto hace tu código más seguro y evita errores accidentales al modificar datos desde fuera.

Analogía

Es como una libreta donde apuntas nombres únicos y... plastificas las páginas. Nadie puede escribir, arrancar ni corregir nada más.

2. Crear un ReadOnlySet

La forma más fácil de crear un conjunto inmutable es usar el método de extensión:


var colors = new[] { "Rojo", "Verde", "Azul", "Verde" };
var readOnlyColors = colors.ToReadOnlySet();

// Ahora aquí solo hay valores únicos y no se puede modificar:
foreach (var color in readOnlyColors)
    Console.WriteLine(color);

Salida:

Rojo
Verde
Azul

También puedes usar el constructor directo (si lo necesitas):


var set = new ReadOnlySet<int>(new[] {1, 2, 2, 3, 5, 1}); // Igual solo habrá 1,2,3,5

ReadOnlySet en Microsoft Docs

3. Propiedades y métodos principales

  • Solo lectura (immutable)
  • Count — número de elementos
  • Contains(item) — comprobar si existe un elemento
  • Soporta consultas LINQ (IEnumerable<T>)
  • Búsqueda rápida, pero no permite añadir, eliminar ni limpiar

Ejemplo:


if (readOnlyColors.Contains("Rojo"))
    Console.WriteLine("¡Rojo está en la lista!");

No puedes hacer esto:


// ¡Error de compilación!
readOnlyColors.Add("Amarillo");

4. ¿Dónde puede servir?

Muy a menudo necesitas exponer información como un conjunto, pero no quieres que nadie pueda modificarlo por accidente (o a propósito). Por ejemplo:

  • Devolver la lista de roles de usuario soportados
  • Lista de extensiones de archivo permitidas
  • Lista de parámetros de configuración únicos que no se pueden cambiar

Ejemplo en nuestra app: supón que hay una lista de departamentos permitidos:


public static ReadOnlySet<string> Departments { get; } =
    new[] { "Recursos Humanos", "Desarrollo", "Contabilidad" }.ToReadOnlySet();

Ahora nadie puede cambiar la lista de departamentos desde fuera.

5. Visualización: diferencia con HashSet normal


graph LR
    A[HashSet] -- Add/Remove/Contains --> B((Elementos))
    C[ReadOnlySet] -- Only Contains --> D((Elementos))
HashSet se puede modificar, ReadOnlySet — ¡nunca!

3. OrderedDictionary vs. ReadOnlySet: tabla comparativa

Colección ¿Guarda pares? ¿Garantiza orden? ¿Se puede modificar? Búsqueda por clave Búsqueda por índice Escenarios
OrderedDictionary Sí "clave-valor" Mapas, configuraciones, informes
ReadOnlySet No, solo valores No No No Conjuntos seguros, constantes
HashSet No, solo valores No No Conjuntos donde necesitas modificar
Dictionary Sí "clave-valor" No No Mapas sin requisitos de orden
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION