c# performance dynamic reflection runtime

c# - La mejor forma de crear una instancia de tipo determinado en tiempo de ejecución



performance dynamic (7)

El problema aquí es que nunca se puede saber el tipo de DerivedClass en tiempo de compilación.

Sin embargo, puedes hacer este tipo de cosas:

BaseClass obj = new DerivedClass();

Esto se implementa de esta manera:

BaseClass obj = (BaseClass)Activator.CreateInstance(this.GetType());

Esta llamada fallará si el DerivedClass no tiene constructores sin parámetros.

Esta pregunta ya tiene una respuesta aquí:

¿Cuál es la mejor manera (en .NET 4) para crear una instancia de un tipo determinado en tiempo de ejecución.

Tengo un método de instancia que, aunque actúe sobre un objeto BaseClass, puede ser llamado por instancias de sus clases derivadas. Necesito crear otra instancia del mismo tipo dentro del método. La sobrecarga del método para cada clase derivada no es práctica, ya que está bastante involucrado y sería más eficiente mantener la implementación única.

public class BaseClass { //constructors + properties + methods etc public SomeMethod() { //some code DerivedClass d = new DerivedClass(); //ideally determine the DerivedClass type at run-time } }

He leído un poco sobre la reflexión o el uso de la palabra clave dinámica, pero no tengo experiencia con estos.


Está buscando Activator.CreateInstance (también hay otras sobrecargas, como esta que acepta argumentos de constructor). Entonces podrías escribir

var anotherOneLikeMe = Activator.CreateInstance(this.GetType());

Puede haber un problema aquí en el sentido de que anotherOneLikeMe se va a escribir como object , por lo tanto, a menos que pretenda convertirlo en una clase base común (por ejemplo, BaseClass en su ejemplo) no hay mucho que pueda hacer con él.


Esto realmente depende de lo que quiere decir con "tiempo de ejecución" y cuáles son los objetivos. Por ejemplo, Jon y Bas han tenido la idea de usar Reflection para vincular tarde una clase en particular y hacer que se instanciara en Runtime. Esta es ciertamente una idea e incluso puedes descubrir los métodos en el objeto en tiempo de ejecución, si ese es tu objetivo

Si está utilizando interfaces, tiene un par de opciones adicionales. El Marco de Extensibilidad de Microsoft (o MEF) podría ser una opción que desea ver, ya que incluye la detección y creación de instancias en el tiempo de ejecución. La desventaja es que la clase descubierta debe cumplir con la interfaz correcta, pero esto no es un problema real en la mayoría de los casos.

Si conoce las clases que está cargando, y tienen la misma interfaz (tema común), pero desea instanciar diferentes clases en tiempo de ejecución, los contenedores IoC son una opción. Esto no es particularmente por lo que preguntas.

La palabra clave dinámica no es lo que estás buscando. Se carga en tiempo de ejecución, pero el dianmic se trata más de que el compilador no compruebe si realmente existen los métodos que está llamando. Hecho incorrectamente, puede terminar con una explosión interesante cuando llama a un método que no existe. La principal motivación que he visto para dyanamic es la interacción con un lenguaje dinámico, como IronPython.


Sé que esto fue marcado como reflejo, pero generalmente veo la reflexión como último recurso por razones de rendimiento y complejidad. Hay algunos casos en los que su diseño / uso requiere reflexión; Sin embargo, ofreceré algunas alternativas para su consideración:

Use un Func fábrica:

public void SomeMethod(Func<BaseClass> createDerived) { BaseClass d = createDerived(); }

Haga que su método use un tipo genérico restringido:

public void SomeMethod<TDerived>() where TDerived : BaseClass, new() { TDerived d = new TDerived(); }

Bajo las cubiertas, esta última alternativa hace uso de Activator.CreateInstance como otros han sugerido. Prefiero el último a la reflexión porque ambos requieren un constructor sin parámetros, pero el compilador impone la restricción de que el tipo derivado debe tener un constructor sin parámetros, mientras que el enfoque de reflexión da como resultado una excepción de tiempo de ejecución.


Si bien es necesario utilizar Activator.CreateInstance, es posible que desee examinar específicamente el Activator.CreateInstance (String, String) que se puede invocar con el nombre de la clase que puede conocer durante el tiempo de ejecución.

Esto será en gran medida beneficioso si está creando instancias de tipos derivados en el tipo de base. Si vas a llamar a SomeMethod desde el tipo derivado en sí mismo, entonces las respuestas previas que usan this.GetType() deberían ser suficientes.


public void SomeMethod() { object x =Activator.CreateInstance(this.GetType()); }

Esto debería crear una nueva instancia, por otro lado, me pregunto por qué intentas hacer esto.


La mejor forma de que el rendimiento cree repetidamente instancia en tiempo de ejecución es la expresión compilada:

static readonly Func<X> YCreator = Expression.Lambda<Func<X>>( Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes)) ).Compile(); X x = YCreator();

Estadísticas (2012):

Iterations: 5000000 00:00:00.8481762, Activator.CreateInstance(string, string) 00:00:00.8416930, Activator.CreateInstance(type) 00:00:06.6236752, ConstructorInfo.Invoke 00:00:00.1776255, Compiled expression 00:00:00.0462197, new

Estadísticas (2015, .net 4.5, x64):

Iterations: 5000000 00:00:00.2659981, Activator.CreateInstance(string, string) 00:00:00.2603770, Activator.CreateInstance(type) 00:00:00.7478936, ConstructorInfo.Invoke 00:00:00.0700757, Compiled expression 00:00:00.0286710, new

Estadísticas (2015, .net 4.5, x86):

Iterations: 5000000 00:00:00.3541501, Activator.CreateInstance(string, string) 00:00:00.3686861, Activator.CreateInstance(type) 00:00:00.9492354, ConstructorInfo.Invoke 00:00:00.0719072, Compiled expression 00:00:00.0229387, new

Código completo:

public static X CreateY_New() { return new Y(); } public static X CreateY_CreateInstance() { return (X)Activator.CreateInstance(typeof(Y)); } public static X CreateY_CreateInstance_String() { return (X)Activator.CreateInstance("Program", "Y").Unwrap(); } static readonly System.Reflection.ConstructorInfo YConstructor = typeof(Y).GetConstructor(Type.EmptyTypes); static readonly object[] Empty = new object[] { }; public static X CreateY_Invoke() { return (X)YConstructor.Invoke(Empty); } static readonly Func<X> YCreator = Expression.Lambda<Func<X>>( Expression.New(typeof(Y).GetConstructor(Type.EmptyTypes)) ).Compile(); public static X CreateY_CompiledExpression() { return YCreator(); } static void Main(string[] args) { const int iterations = 5000000; Console.WriteLine("Iterations: {0}", iterations); foreach (var creatorInfo in new [] { new {Name = "Activator.CreateInstance(string, string)", Creator = (Func<X>)CreateY_CreateInstance}, new {Name = "Activator.CreateInstance(type)", Creator = (Func<X>)CreateY_CreateInstance}, new {Name = "ConstructorInfo.Invoke", Creator = (Func<X>)CreateY_Invoke}, new {Name = "Compiled expression", Creator = (Func<X>)CreateY_CompiledExpression}, new {Name = "new", Creator = (Func<X>)CreateY_New}, }) { var creator = creatorInfo.Creator; var sum = 0; for (var i = 0; i < 1000; i++) sum += creator().Z; var stopwatch = new Stopwatch(); stopwatch.Start(); for (var i = 0; i < iterations; ++i) { var x = creator(); sum += x.Z; } stopwatch.Stop(); Console.WriteLine("{0}, {1}", stopwatch.Elapsed, creatorInfo.Name); } } public class X { public X() { } public X(int z) { this.Z = z; } public int Z; } public class Y : X { }