Cómo crear una nueva instancia de objeto a partir de un Tipo
Es posible que no siempre se conozca el Tipo
de un objeto en tiempo de compilación, sino que se necesite crear una instancia del Tipo
. ¿Cómo se obtiene una nueva instancia de un objeto a partir de un Tipo
?
689
12
La clase
Activator
dentro del espacio de nombres raízSystem
es bastante potente.Hay un montón de sobrecargas para pasar parámetros al constructor y demás. Consulta la documentación en:
http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx>
o (nueva ruta)
He aquí algunos ejemplos sencillos:
La clase "Activador" tiene una variante genérica que lo hace un poco más fácil:
La expresión compilada es la mejor manera! (para que la actuación cree repetidamente la instancia en tiempo de ejecución).
Estadísticas (2012):
Estadísticas (2015, .net 4.5, x64):
Estadísticas (2015, .net 4.5, x86):
Estadísticas (2017, LINQPad 5.22.02/x64/.NET 4.6):
Estadísticas (2019, x64/.NET 4.8):
Estadísticas (2019, x64/.NET Core 3.0):
Código completo:
Una implementación de este problema es intentar llamar al constructor sin parámetros del Tipo:
Aquí está el mismo enfoque, contenido en un método genérico:
Es bastante simple. Asume que tu nombre de clase es "Car" y el espacio de nombres es "Vehicles", entonces pasa el parámetro como "Vehicles.Car" que devuelve el objeto de tipo "Car". Así puedes crear cualquier instancia de cualquier clase dinámicamente.
Si su [Nombre Completamente Calificado][1](es decir,
Vehículos.Car
en este caso) está en otro ensamblaje, elTipo.GetTipo
será nulo. En tales casos, tienes que hacer un bucle a través de todos los ensamblajes y encontrar elTipo
. Para ello puedes usar el siguiente códigoY puedes obtener la instancia llamando al método anterior.
[1]: https://msdn.microsoft.com/en-us/library/dfb3cx8s%28v=vs.71%29.aspx
Si esto es para algo que será llamado muchas veces en una instancia de la aplicación, es mucho más rápido compilar y almacenar en caché el código dinámico en lugar de utilizar el activador o
ConstructorInfo.Invoke()
. Dos opciones fáciles para la compilación dinámica son las Expresiones Linq compiladas o algunos simples opcodesIL
yDynamicMethod
. De cualquier manera, la diferencia es enorme cuando empiezas a entrar en bucles apretados o en llamadas múltiples.Si quieres usar el constructor por defecto, entonces la solución usando "System.Activator" presentada anteriormente es probablemente la más conveniente. Sin embargo, si el tipo carece de un constructor por defecto o tienes que usar uno no por defecto, entonces una opción es usar la reflexión o
Sistema.ComponenteModelo.TipoDescriptor
. En caso de reflexión, es suficiente con saber sólo el nombre del tipo (con su espacio de nombres).Ejemplo usando la reflexión:
Ejemplo usando "TypeDescriptor":
¿Funcionaría el genérico
T t = new T();
?Sin el uso de la Reflexión:
Dado este problema, el Activador funcionará cuando haya un ctor sin parámetros. Si esto es una restricción, considere el uso de
Puedo cruzar esta pregunta porque estaba buscando implementar un método simple de Clono-Objeto para una clase arbitraria (con un constructor por defecto)
Con el método genérico se puede requerir que el tipo implemente New().
Con el no genérico asume que el tipo tiene un constructor por defecto y coge una excepción si no lo hace... 39.