miércoles, 23 de diciembre de 2009

Obtener las clases derivadas de una clase base

Problemática

Tenemos un conjunto de clases que heredan todas de la misma clase base y al iniciar el programa necesitamos inicializar y configurar una instancia de cada una de las clases hijas. Hasta ahora cuando necesitábamos definir una clase hija teníamos que:
1. Crear la nueva clase.
2. Ir al método que inicializa las clases hijas.
3. Ir al método donde se configuran las clases hijas.

¡Un lío! .. y más si tenemos en cuenta que es algo que se hace esporádicamente.

Nuestro deseo era que cuando alguien necesite implementar la definición de una nueva clase hija simplemente deba hacer eso: definirla y punto, del resto de tareas (inicializar y configurar) que se preocupe el programa.

Solución

La solución pasa por usar Reflection. Realizamos una búsqueda en nuestro Assembly de todas las clases existentes que heredan de la clase base y las instanciamos, ¡Así de fácil!

Ejemplo

Primero creamos la clase base y las derivadas:

Public MustInherit Class ClaseBase

Public MustOverride Sub Metodo()

End Class

Public Class ClaseQueHerada
Inherits ClaseBase

Public Sub New()
Console.WriteLine("Constructor de la ClaseQueHerada")
End Sub

Public Overrides Sub Metodo()
Console.WriteLine("ClaseQueHerada.Metodo")
End Sub

End Class

Public Class OtraClaseQueHerada
Inherits ClaseBase

Public Sub New()
Console.WriteLine("Constructor de la OtraClaseQueHerada")
End Sub

Public Overrides Sub Metodo()
Console.WriteLine("OtraClaseQueHerada.Metodo")
End Sub

End Class

En el código siguiente podemos ver como buscamos las clases derivadas, instanciamos y ejecutamos los métodos comunes y todo en tiempo de ejecución.


Module Main

Sub Main()

'Accedemos al Assembly que estamos ejecutando
Dim CurrentAssembly As Assembly = System.Reflection.Assembly.GetExecutingAssembly()
'Con LINQ obtenemos la lista de classes que heredan de ClaseBase, gracias al método IsSubClassOf
Dim q = From t As Type In CurrentAssembly.GetTypes() _
Where t.IsSubclassOf(GetType(ClaseBase))

For Each o As Type In q
'Para cada una de las clases hijas la instaciamos y ejecutamos el método
Console.WriteLine(o.Name)
Dim der As ClaseBase = CurrentAssembly.CreateInstance(o.FullName, True)
der.Metodo()
Next

Console.Read()

End Sub

Con este método de acceso a las clases hijas te puedes ahorrar mucho trabajo.