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:
'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:
'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...
Debug.Print(OBJ.GetType.ToString)
...obtendremos...
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: .NET, activator, createinstance, gettype, type, visual basic
Diciembre 17th, 2008 at 09:42
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
Diciembre 17th, 2008 at 09:53
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.