Diccionarios con polimorfismo en C#

Clase 16 de 35Curso de C# con .Net Core 2.1

Resumen

Implementa un diccionario robusto en C# para organizar tu modelo escolar con claves de tipo string y colecciones tipadas. Aquí verás cómo evitar excepciones por llaves duplicadas, cómo aprovechar el polimorfismo y por qué conviene devolver una interfaz como IEnumerable en lugar de una List concreta. Todo, paso a paso, desde Visual Studio.

¿Qué construimos con un diccionario string a objetos en C#?

Un método que devuelva un Dictionary<string, IEnumerable<ObjetoEscuelaBase>>. La clave es un string (por ejemplo, "escuela" o "cursos") y el valor es una colección de ObjetoEscuelaBase. Esta decisión permite indexar los distintos tipos del dominio escolar con una sola estructura.

  • Claves legibles: "escuela", "cursos".
  • Valores consistentes: siempre una colección de ObjetoEscuelaBase.
  • Método claro: get diccionario de objetos.

Ejemplo en C#:

public Dictionary<string, IEnumerable<ObjetoEscuelaBase>> GetDiccionarioDeObjetos() { var diccionario = new Dictionary<string, IEnumerable<ObjetoEscuelaBase>>(); // escuela: un único objeto envuelto en colección. diccionario.Add("escuela", new ObjetoEscuelaBase[] { escuela }); // cursos: conversión explícita a la jerarquía base. IEnumerable<ObjetoEscuelaBase> cursosComoBase = cursos.Cast<ObjetoEscuelaBase>(); diccionario.Add("cursos", cursosComoBase); return diccionario; }

¿Cómo evitamos colisiones de llave y valores incompatibles?

Agregar varias veces la misma clave (por ejemplo, "cursos") provoca una excepción por llave duplicada. La solución no es inventar claves como "curso2" o "curso3", sino usar una sola clave y entregar todos los cursos como colección.

  • Un valor por clave: evita repetir "cursos" para cada curso.
  • Colección única: agrupa todos los cursos debajo de "cursos".
  • Envoltura mínima: para "escuela", usa un array de una posición.

Fragmento clave:

// Escuela como colección (array de 1 elemento). diccionario.Add("escuela", new ObjetoEscuelaBase[] { escuela }); // Todos los cursos en una sola entrada. diccionario.Add("cursos", cursos.Cast<ObjetoEscuelaBase>());

¿Por qué usar IEnumerable y hacer casting con polimorfismo?

Aunque un curso hereda de ObjetoEscuelaBase, una List<Curso> no es una List<ObjetoEscuelaBase>. No existe conversión implícita ni explícita entre listas genéricas de tipos distintos. Por eso, cuando trabajas con colecciones derivadas, C# exige conversión a una interfaz común.

  • Polimorfismo: Curso es compatible con ObjetoEscuelaBase.
  • Colecciones genéricas: List de derivados no hereda de List de base.
  • Interfaz genérica: usa IEnumerable<ObjetoEscuelaBase> en el diccionario.
  • Conversión clara: aplica .Cast<ObjetoEscuelaBase>() a la colección de cursos.

Código ilustrativo:

// List<Curso> cursos; // colección concreta // Convertimos al tipo base, como interfaz (no como List). IEnumerable<ObjetoEscuelaBase> cursosComoBase = cursos.Cast<ObjetoEscuelaBase>(); // El diccionario expone IEnumerable, compatible con el resultado de Cast. var diccionario = new Dictionary<string, IEnumerable<ObjetoEscuelaBase>> { { "escuela", new ObjetoEscuelaBase[] { escuela } }, { "cursos", cursosComoBase } };

Puntos clave del diseño:

  • Exponer interfaces: IEnumerable ofrece flexibilidad y encaja con .Cast<>.
  • Evitar casting inválido: no intentes convertir List<Curso> a List<ObjetoEscuelaBase>.
  • Uniformidad: el valor del diccionario siempre es colección, incluso para un único elemento.

¿Qué habilidades y conceptos practicas aquí?

  • Diseño de API: firmas claras que devuelven interfaces.
  • Estructuras de datos: Dictionary con clave string y valor colección tipada.
  • Polimorfismo práctico: derivados convertidos a la clase base.
  • Conversión explícita: uso de .Cast<> con colecciones.
  • Manejo de errores: prevención de excepción por llave duplicada.

¿Te gustaría ver variantes con otras colecciones o claves adicionales del dominio? Cuéntame en comentarios qué caso quieres mapear y lo construimos juntos.