Cómo crear un reporteador en C sharp

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

Resumen

Crear consultas claras y reportes útiles en C sharp es más sencillo cuando estructuramos bien los datos y aplicamos validaciones sólidas. Aquí construimos un reporteador que usa un diccionario indexado por una enumeración, maneja excepciones de forma explícita y expone resultados como IEnumerable para mantener el encapsulamiento.

¿Cómo diseñar el reporteador en C sharp para consultas y reportes?

El objetivo es centralizar las consultas en una clase llamada Reporteador, dentro del namespace correcto (por ejemplo, CoreEscuela.App). La decisión clave: recibir en el constructor un diccionario cuyas llaves son una enumeración (las entidades) y cuyos valores son listas de objetos de la escuela. Así, el reporteador puede generar reportes reutilizables a partir de datos ya construidos.

  • Clase de orquestación: agrupa lógica de consultas y reportes.
  • Entrada única: un diccionario indexado por enum con listas de objetos.
  • Menos acoplamiento: el reporteador no crea datos, solo los consulta.

Ejemplo base de la clase:

using System;
using System.Collections.Generic;

namespace CoreEscuela.App
{
    public class Reporteador
    {
        private readonly Dictionary<TipoEntidad, IEnumerable<ObjetoEscuela>> _diccionario;

        public Reporteador(Dictionary<TipoEntidad, IEnumerable<ObjetoEscuela>> diccionario)
        {
            _diccionario = diccionario ?? throw new ArgumentNullException(nameof(diccionario));
        }
    }
}

¿Qué rol cumple el diccionario con enumeración como llave?

El diccionario concentra “todo” lo que la aplicación generó: cursos, alumnos, evaluaciones, etc., indexado por una enumeración. La búsqueda es directa: se consulta la llave correspondiente a Evaluación y se obtiene su lista. Esto separa el “dónde están los datos” del “cómo los uso” y habilita reportes consistentes.

  • Llave: una enumeración que representa la entidad (p. ej., Evaluación).
  • Valor: lista de objetos de esa entidad.
  • Beneficio: acceso rápido y tipado firme.

¿Por qué el constructor valida nulos con ArgumentNullException y nameof?

Para evitar errores silenciosos, si el diccionario llega nulo, el constructor falla con throw new ArgumentNullException(nameof(diccionario)). Así se detiene la ejecución temprano y el mensaje es claro.

  • Uso de throw explícito.
  • Excepción específica: ArgumentNullException en lugar de la genérica.
  • Mensaje auto-documentado con nameof.

Fragmento ilustrativo:

public Reporteador(Dictionary<TipoEntidad, IEnumerable<ObjetoEscuela>> diccionario)
{
    _diccionario = diccionario ?? throw new ArgumentNullException(nameof(diccionario));
}

¿Cómo organizar campos privados y namespaces?

Por convención, los campos privados inician con underscore. Esto facilita lectura y mantenimiento. Además, es clave ubicar la clase en el namespace correcto según la carpeta del proyecto para evitar errores de referencia.

  • Campo privado: _diccionario.
  • Namespace consistente con la estructura del proyecto.
  • Constructor con nivel de protección público para poder instanciar.

Instanciación típica desde el programa:

var reporteador = new Reporteador(engine.GetDiccionarioDeObjetos());

¿Qué debes saber de clases estáticas y constructores estáticos en C sharp?

Se intentó hacer el reporteador como clase estática, pero se descartó para no complicar. Aun así, quedaron reglas importantes.

  • Una clase estática requiere constructor estático.
  • El constructor estático no admite parámetros y no lleva modificadores de acceso.
  • Útil para inicializaciones globales, pero innecesario si se requiere inyección de dependencias o parámetros.

Ejemplo de constructor estático válido:

class Curso
{
    static Curso()
    {
        // Inicialización estática.
    }
}

¿Cuáles son las reglas del constructor estático?

  • Sin parámetros: configuración única y automática.
  • Sin modificadores de acceso: el lenguaje lo impone.
  • Se ejecuta una vez, antes del primer uso del tipo.

¿Cuándo evitar una clase estática para simplificar?

Cuando necesitas recibir dependencias por constructor (como el diccionario) o probar con diferentes entradas, una clase no estática es más flexible. Así mantienes el código claro y evitas límites innecesarios.

¿Cómo exponer evaluaciones con IEnumerable sin romper el encapsulamiento?

Al exponer colecciones hacia el exterior, es buena práctica retornar IEnumerable o una lista de solo lectura. Así comunicas “esto se recorre, no se modifica” y proteges el estado interno.

  • Contrato mínimo: IEnumerable para iterar.
  • Evita mutaciones no controladas.
  • Facilita pruebas y composición de consultas.

Implementación de la consulta de evaluaciones:

public IEnumerable<Evaluacion> GetListaDeEvaluaciones()
{
    // Asume que la llave TipoEntidad.Evaluacion existe y está cargada.
    return (IEnumerable<Evaluacion>) _diccionario[TipoEntidad.Evaluacion];
}

Y al usar el diccionario, procede con cautela: si la llave no existe o la colección no se cargó, se lanzará una excepción. Por eso es recomendable validar antes de acceder directamente cuando no controlas todo el flujo de carga.

  • Verifica la existencia de la llave antes de acceder.
  • Evita suposiciones sobre el estado de carga.
  • Maneja errores de forma explícita para diagnósticos claros.

¿Te gustaría que agreguemos filtros por curso, alumno o rangos de fechas en los reportes? Cuéntame qué necesitas y seguimos construyendo juntos.

      Cómo crear un reporteador en C sharp