Implementar interfaces con objetos anónimos en C#

No suelo echar de menos cosas de la época (ya lejana) en que programaba en java, pero hace poco tuve un caso en que me hubiera gustado poder usar en C# algo parecido a las clases anónimas de java.

Por si acaso alguien que no ha tenido la suerte la desgracia la ocasión de haber trabajado con java, una clase anónima es una clase que se define para realizar una tarea concreta heredando de otra clase y sólo se usa en el punto en que define. Por ejemplo:

component.setReporter(new Reporter() {
    public void writeError(String msg) {...}
    public void writeMsg(String msg) {...}
});

En este caso, se define una clase que hereda de la clase Reporter y redefine los métodos writeError y writeMessage para un caso de uso concreto.

En java es una construcción muy frecuente, pero la mayoría de las veces en C# se puede sustituir por eventos o por delegates, por lo que no se suele echar en falta.

Sin embargo, hay veces que necesitamos satisfacer alguna dependencia y no queremos tener que definir una clase entera porque sólo lo vamos a hacer en un punto concreto de la aplicación. Aprovechando las técnicas de duck typing que vimos en el post anterior podemos conseguir algo parecido.

Duck Typing de objetos anónimos en C#

En C# podemos definir clases anónimas con propiedades, pero no podemos añadirles métodos, lo que hace que no sean válidos para el caso que exponía antes en que necesitamos que un objeto implemente un interfaz determinado.

Con el código que vimos en el post anterior podemos aplicar duck typing al objeto anónimo y conseguir que funcione como si implementase un interface, aunque sólo con propiedades:

interface INamed
{
    string Name { get; }
}

INamed named = DuckType.As<INamed>(new 
{
    Name = "Rocinante"
});

«Implementando» interfaces con objetos anónimos

Dándole una vuelta de tuerca a la idea, podemos conseguir “implementar” un interfaz con un objeto anónimo. Digo “implementar”, entre comillas, porque realmente no vamos a implementar el interfaz, pero podemos simularlo utilizando propiedades de tipo Func o Action para representar los métodos del interfaz:

interface ICalculator
{
    int Sum(int a, int b);
    int Div(int a, int b);
}

ICalculator c = DuckType.As<ICalculator>(new
{
    Sum = new Func<int, int, int>((a,b) => a+b);
    Div = new Func<int, int, int>((a,b) => a/b);
});

Para poder implementar esto, hace falta modificar el código que veíamos en el post anterior para que cuando encuentre un método en el interface que no esté en el objeto al que aplicamos el duck typing, intente buscar una propiedad con el mismo nombre y un tipo de Action o Func compatible con la signatura del método.

El código es un poco largo para ponerlo aquí, pero lo podéis encontrar completo en este gist.

Conclusiones

Aunque no es exactamente igual que las clases anónimas de java, con la técnica explicada en este post podemos conseguir algo bastante similar.

Es cierto que perdemos la comprobación de tipos y podemos tener problemas si cambiamos el interfaz y se nos olvida actualizar el objeto anónimo, pero no debería ser muy problemático porque tampoco deberíamos tener la aplicación llena de «clases anónimas».