Decidir clase en tiempo de ejecución en .NET.

En ocasiones puede resultarnos imprescindible no determinar la clase de la que un objeto va a ser instancia hasta que estemos en tiempo de ejecución. Para ello podemos valernos de la clase Activator y de su método CreateInstance, que nos permiten pasarle una clase para que nos devuelva un objeto de esa clase.

Podemos por ejemplo crearnos una función sencilla como esta...

'----------------------------------------------------------------
' Creates an instance of specified class and returns that object.
'----------------------------------------------------------------
Public Function CreateInstance(ByVal T As Type) As Object
    Return Activator.CreateInstance(T)
End Function

...que podríamos tener encapsulada como método de alguna clase que nos permitiera hacer determinadas acciones con objetos, esto ya a gusto de cada cual.

Una vez tenemos esta función podemos llamarla de varias maneras. La primera, si tenemos otro objeto de la misma clase de la que ahora queremos obtener una instancia:

Dim OBJ As Object

'Option 1. We already have an object of that class.
Dim C1 As New Class1()
OBJ = Me.CreateInstance(C1.GetType())

La segunda, si no tenemos ningún objeto pero conocemos el nombre de la clase en cuestión:

Dim OBJ As Object

'Option 2. We haven't any object of that class.
OBJ = Me.CreateInstance(Type.GetType("AlbertMata.Class2"))

'But be careful because this would fail:
'OBJ = Me.CreateInstance(Type.GetType("Class2"))

Como aparece en el código, conviene remarcar que el nombre de la clase debe incorporar el espacio de nombres, de lo contrario provocará una excepción.

En ambos casos, si una vez creado el objeto -que si nos fijamos lo habíamos declarado como Object y lo habíamos instanciado a través de un método que también devolvía un Object- consultamos su tipo exacto...

'Checking exact type for object.
Debug.Print(OBJ.GetType.ToString)

...obtendremos...

AlbertMata.Class2

Particularmente este sistema me ha venido bien para alguna travesura que quería hacer con formularios, pero creo que en más ocasiones podrá serme útil.

Tags: , , , , ,

2 Responses to “Decidir clase en tiempo de ejecución en .NET.”

  1. Luis Medel se atrevió a comentar:

    Si quieres, puedes ir un poco más lejos y añadir soporte para "scripts" en tu aplicacon. Así aligeras un poco la ejecución por no tener cargado todo en cada momento. Es muuuuy útil.

    Por si te interesa, te pego el código (algo modificado, para que tenga sentido) de un cargador dinámico que hice para un raytracer que escribí en C#.


    // Una clase cualquira que nos va a servir para localizar el Assembly
    Scene cls = new Clase ();
    Assembly me = cls.GetType ().Assembly;

    CompilerParameters parms = new CompilerParameters();
    parms.GenerateExecutable = false;
    parms.GenerateInMemory = true;
    parms.IncludeDebugInformation = false;

    // Añadimos las referencias necesarias
    parms.ReferencedAssemblies.Add ("System.dll");
    parms.ReferencedAssemblies.Add ("System.Drawing.dll");
    parms.ReferencedAssemblies.Add (me.Location);

    ICodeCompiler compiler = CodeDomProvider.CreateProvider ("CSharp").CreateCompiler ();
    CompilerResults results = compiler.CompileAssemblyFromSource (parms, STRING_CON_EL_CODIGO_FUENTE);

    if (results.Errors.Count == 0)
    {
    Assembly asm = results.CompiledAssembly;
    // Devolvemos una instancia de la clase NOMBRE_DE_CLASE_DESEADA
    return asm.CreateInstance ("NOMBRE_DE_CLASE_DESEADA", true);
    }

    foreach (CompilerError cerr in results.Errors)
    {
    Console.WriteLine (cerr.ErrorText);
    }
    return null;

    STRING_CON_EL_CODIGO_FUENTE y NOMBRE_DE_CLASE_DESEADA creo que son autoexplicativos ;)

  2. Albert Mata se atrevió a comentar:

    Caramba, qué interesante... Haré pruebas con ello, sí señor. ¡Gracias!

    Por cierto, no sé por qué tu comentario quedó en espera de aprobación, sorry.

Leave a Reply