CodeGym /Cursos /C# SELF /Recomendaciones para organizar el código

Recomendaciones para organizar el código

C# SELF
Nivel 54 , Lección 1
Disponible

1. Estilo de declaración y nombrado de eventos

Los eventos no son solo delegados. Son una entidad separada para la comunicación entre partes de la aplicación, y su declaración debe ser clara.

Usa el tipo de delegado correcto

En el 99% de los casos usa los delegados estándar:

  • EventHandler — para eventos sin datos.
  • EventHandler<TEventArgs> — cuando hace falta pasar parámetros.

La estandarización facilita el mantenimiento del código e integración con librerías de .NET. No inventes tu propio delegado si sirve EventHandler.


public event EventHandler SomethingHappened; // Sin datos
public event EventHandler<MyEventArgs> DataReceived; // Hay datos adicionales

Si necesitas personalización especial — declara un delegado propio, pero es raro.

Nombrado de eventos

En .NET los eventos se nombran en pasado: Completed, Clicked, Changed, Received. Esto enfatiza que el hecho ya ocurrió.

Ejemplos:


public event EventHandler DataLoaded;    // Los datos fueron cargados
public event EventHandler<MessageEventArgs> MessageReceived; // Mensaje recibido
public event EventHandler Saving;        // Se inició el proceso de guardado

A veces se usa la forma Changing para eventos "antes" del cambio, para dar oportunidad de intervenir.

2. Organización de la clase publicadora: método virtual OnEvent

Siempre añade un método protected virtual que invoque el evento: punto central de invocación, extensibilidad vía herencia y comportamiento predecible.


public class FileLoader
{
    public event EventHandler<FileLoadedEventArgs> FileLoaded;

    protected virtual void OnFileLoaded(FileLoadedEventArgs e)
    {
        FileLoaded?.Invoke(this, e);
    }

    public void Load(string filename)
    {
        // ... lógica de carga de archivo ...
        OnFileLoaded(new FileLoadedEventArgs(filename));
    }
}

public class FileLoadedEventArgs : EventArgs
{
    public string FileName { get; }
    public FileLoadedEventArgs(string fileName) => FileName = fileName;
}

Que solo OnFileLoaded invoque el evento — así es más fácil mantenerlo y testearlo.

3. Reglas de suscripción y desuscripción: ciclo de vida, IDisposable

Si la vida del suscriptor es menor que la del publicador, debes desuscribirte antes de destruir el suscriptor. Es conveniente implementar IDisposable y desuscribirse en Dispose().


public class TemporaryListener : IDisposable
{
    private readonly Publisher _publisher;

    public TemporaryListener(Publisher publisher)
    {
        _publisher = publisher;
        _publisher.DataReceived += HandleData;
    }

    private void HandleData(object sender, EventArgs e)
    {
        // Trabajo con los datos
    }

    public void Dispose()
    {
        _publisher.DataReceived -= HandleData;
    }
}

// Uso con using:
using (var listener = new TemporaryListener(myPublisher))
{
    // listener escucha eventos aquí
}
// Al salir del using - Dispose es llamado, la dessuscripción ocurrió

Si olvidas desuscribirte, el publicador mantendrá la referencia al delegado del suscriptor — tendrás fugas de memoria y "objetos zombie".

4. Invocación segura frente a hilos

En código multihilo los suscriptores pueden añadirse/quitándose en paralelo con la invocación del evento. Esto puede causar race conditions y NullReferenceException. Usa el patrón seguro: copia el delegado a una variable local.


protected virtual void OnSomethingHappened()
{
    EventHandler handler = SomethingHappened;
    handler?.Invoke(this, EventArgs.Empty);
}

Con C# 6+ es suficiente:


SomethingHappened?.Invoke(this, EventArgs.Empty);

5. Usa EventArgs en vez de object

No pases datos vía object ni campos de la clase. Usa tipado estricto mediante subclases de EventArgs.


public class DownloadCompletedEventArgs : EventArgs
{
    public string FileName { get; }
    public long Size { get; }
    public DownloadCompletedEventArgs(string fileName, long size)
    {
        FileName = fileName;
        Size = size;
    }
}

public event EventHandler<DownloadCompletedEventArgs> DownloadCompleted;

6. Documenta eventos y suscriptores

Documenta: cuándo se invoca el evento, el significado de los campos de EventArgs, si hace falta desuscribirse y cuándo.


/// <summary>
/// El evento ocurre después de una carga exitosa de datos.
/// </summary>
public event EventHandler<DataLoadedEventArgs> DataLoaded;

7. Recomendaciones resumidas sobre la arquitectura de eventos

Separa responsabilidades

El publicador solo notifica del hecho. El suscriptor decide cuándo suscribirse y desuscribirse.

Evita "bombardear" con eventos

No generes el mismo evento decenas de veces por segundo sin necesidad — es carga innecesaria.

No uses eventos para comunicación bidireccional

Los eventos son para el esquema "uno notifica — muchos escuchan". Para comunicación bidireccional considera interfaces, callbacks u otros mecanismos.

No almacenes referencias explícitas a suscriptores en la clase

No mantengas referencias explícitas a los suscriptores — los eventos y delegados se encargan de eso automáticamente.

8. Antipatrons clásicos

Eventos sin tipar


public event Action<object> SomethingHappened; // No está claro qué hay dentro

Malo: se rompe el tipado, hacen falta casts, se pierde mantenibilidad.

Olvidar la desuscripción


public class ShortLivedListener
{
    public ShortLivedListener(Publisher p) =>
        p.DataReceived += DoWork;

    private void DoWork(object sender, EventArgs e) { /* ... */ }
    // No hay Dispose, no hay desuscripción => objetos zombie!
}

Violación de SRP

Clase que es a la vez publicador, suscriptor y handler — mezcla de responsabilidades. Separa responsabilidades.

9. Uso práctico en entrevistas y proyectos

En muchos proyectos con publicación-suscripción, una organización correcta de eventos es clave para escalabilidad y mantenimiento. En entrevistas suelen pedir:

  • implementar un sistema de eventos con tipado correcto,
  • mostrar gestión del ciclo de vida de los suscriptores,
  • explicar la invocación segura frente a hilos.

Código de eventos limpio, documentado y bien organizado te destacará entre los candidatos.

2
Tarea
C# SELF, nivel 54, lección 1
Bloqueada
Organización de eventos con varios suscriptores
Organización de eventos con varios suscriptores
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION