Veamos el siguiente supuesto: Tienes una clase base, de la que heredan digamos siete clases diferentes.
Tienes un vector en el que deseas almacenar objetos que sean del mismo tipo de una de las siete clases derivadas (y sólo de esa), pero en tiempo de programación no sabes a priori de cuál de los siete tipos se trata.
O bien, simplemente quieres crear un objeto de un tipo X, pero a priori no sabes qué tipo X es (entonces puedes considerar que X es una clase derivada de Object, y por tanto se aplica también el supuesto anterior)
¿Cómo entonces puedes crear N objetos del tipo elegido EN TIEMPO DE EJECUCIÓN si a priori no sabías cuál de ellos es?
La respuesta se puede conseguir en el namespace System.Reflection:
La línea de código
AppDomain.CurrentDomain.CreateInstanceAndUnwrap( ObjetoDerivado.GetType().Assembly.FullName, ObjetoDerivado.GetType().FullName );
Nos crea un objeto perteneciente al ensamblado al que pertenece el objeto "ObjetoDerivado", que puede ser de cualquier clase perteneciente a ese ensamblado, y cuyo nombre se puede obtener también fácilmente. El método GetType() nos devuelve un objeto del tipo Type que podemos utilizar para obtener información acerca la clase a la que pertenece un objeto determinado, así como su "clase Base" en caso de herencia.
Como el método "CreateInstanceAndUnwrap" nos devuelve un objeto del tipo "object", debemos hacer un cast explícito si queremos guardar el objeto en un array polimórfico de la clase Base.
Ejemplo:
Tenemos una clase base Cromosoma, y para el laboratorio de Ingeniería Genética en el que trabajamos tenemos CromoPerro, CromoMono y CromoLoro. Todos ellos son clases derivadas de Cromosoma, es decir, que su declaración sería algo así como:
public class CromoPerro: Cromosoma{ ... }
En cualquier momento, en tiempo de ejecución, podemos necesitar guardar 20 Cromosomas del tipo CromoPerro en una probeta (Un array de toda la vida). En tiempo de diseño, no sabemos "a priori" qué cromosomas se pueden guardar en la probeta. Pueden ser CromoPerros, CromoMonos o CromoLoros. Para solucionarlo, decidimos utilizar polimorfismo y declarar un array así:
Cromosoma[] probeta = new Cromosoma[20];
A continuación, un sistema automatizado decide que necesita guardar elementos de la clase CromoPerro para realizar experimentos de mutación con cada uno de ellos. Crea un Cromosoma del tipo CromoPerro
Cromosoma muestra=new CromoPerro();
Y a continuación pulsa el botón "replicar Cromosoma en probeta". El programa no sabe a priori qué tipo de cromosomas se guardan en la "muestra" (bueno, en este sencillo ejemplo sí), entonces para obtener las 20 réplicas del cromosoma hace lo siguiente:
for(int i=0;i<20;i++) probeta[i] = (Cromosoma)AppDomain.CurrentDomain.CreateInstanceAndUnwrap( muestra.GetType().Assembly.FullName, muestra.GetType().FullName );
Una vez realizado, podemos comprobar que los 20 cromosomas de la probeta son del tipo CromoPerro con el siguiente código:
for(int i=0;i<20;i++) MessageBox.Show(probeta[i].getType().ToString());
El cual nos mostrará 20 mensajes diciéndonos lo siguiente: NameSpace.CromoPerro
Utilidad Principal: A lo largo del ciclo de vida de un programa, en caso de utilizar mucho la herencia y polimorfismo, nunca sabes cuándo puedes añadir nuevas clases derivadas. Utilizando técnicas tradicionales, eso significa que tendrías un switch para identificar la clase derivada a la que pertenece un objeto (normalmente identificado mediante un flag), y por tanto, cada vez que necesites crear/guardar en un lugar objetos cuyo tipo no conoces a priori, pero necesitas que sean del mismo tipo original, entonces este fragmento de código te evitará muchos dolores de cabeza con una gran cantidad de "switch"es.
Tal vez sea un snippet de uso demasiado específico, pero desde luego, encontrar esto en la red es una tarea harto complicada (básicamente, cuando me hizo falta buscarlo no lo encontraba en ningún sitio :P)
Comentarios, dudas, erratas, etc son bienvenidas :)
Fullbyte Alchemist