2009-07-10 26 views
9

Ok, entonces todos sabemos que Reflecttion es mucho menos eficiente que "newing" una instancia de clase, y en muchos casos esto está bien dependiendo de los requisitos de la aplicación.¿Cómo crear clases .NET de alto rendimiento utilizando la reflexión?

PREGUNTA: ¿Cómo podemos crear clases .NET de alto rendimiento utilizando una estrategia de enlace tardío (Reflexión).

Tengo un requisito existente que exige que las instancias de clase se creen utilizando reflection (CreateInstance), pero el rendimiento es crítico. En mi situación, estoy creando instancias para cada Mensaje SMS entrante en nuestra aplicación. Durante la producción, esto podría ser fácilmente más de un millón por día.

Me gustaría escuchar y compartir algunas ideas sobre cómo crear clases .NET sin hacer referencia directa a las clases en el código, por ejemplo, utilizando Reflection. También estaba pensando si hay alguna forma de almacenar en caché de alguna forma una fábrica que pueda mejorar el tiempo de "Creación"

+0

espera de C# 4.0, supongo :) –

+4

Cómo sería C# 4.0 ayuda, exactamente? –

+0

El uso de Reflection para crear una instancia de un objeto es trivial en el 99.9% de los casos. La reflexión en .NET es extremadamente rápida, solo escríbela y vuelve más tarde si es un problema. Garantizar que no será –

Respuesta

6

No creo que un millón por día sea demasiado para una simple llamada de reflexión. Creo que está sobre-optimizando, pero de todos modos, como dijo, simplemente cree una clase de fábrica con una sola llamada Activator.CreateInstance y guarde esa en caché. Las instancias reales se crearán utilizando la llamada al método CreateInstance() en el objeto devuelto.

public interface IClassFactory { 
    IClass CreateInstance(); 
} 

public interface IClass { 
    // your actual class interface. 
} 

public class DefaultClassFactory : IClassFactory { 
    public IClass CreateInstance() { 
     return new DefaultClass(); // the implementation class 
    } 
} 

En algún lugar usted tendrá un campo de tipo IClassFactorystatic el que deberá definir una vez con una instancia de los DefaultClassFactory o cualquier otras clases especificadas en el archivo de configuración o lo que sea.

+0

El único inconveniente posible aquí es que si la aplicación es multiproceso, podría tener varias llamadas diferentes utilizando el misma instancia, y termina con instancias con estado mixto. Tal vez devolver un clon del objeto si eso es un problema? – Matt

+0

¿Huh? ¿Por qué? Factory siempre creará una nueva instancia y es seguro para hilos, ya que no tiene un estado interno. –

+1

@Matt dijo una fábrica estática, no la clase en sí misma estática. Las fábricas son fáciles de hacer seguras para hilos. –

11

1 millón al día no es mucho; Solo usaría Activator.CreateInstance (una prueba rápida usando Activator.CreatInstance(Type) muestra que en mi humilde computadora portátil puede crear objetos 1M a partir de Type en ~ 2s).

Reflexiones sobre la creación de objetos de forma rápida:

  • genéricos de uso y la : new() restricción (esfuerzo cero)
  • uso DynamicMethod y escribir la IL (no es difícil)

Una implementación del new enfoque (sin necesidad de la restricción : new() externamente) se muestra aquí: ObjectFactory.cs.

Para un ejemplo IL, ver dapper-dot-net y il.Emit(OpCodes.Newobj, ...)

+1

+1 clase útil. – RichardOD

+1

nueva vía restricción genérica no es particularmente rápido ... – flq

+0

@Frank: solo si su constructor no es particularmente rápido, en cuyo caso nada lo salvará. 'new()' a través de una restricción genérica da como resultado una invocación directa real del constructor, por lo que no se vuelve más rápido que eso. – jerryjvl

5

Algunos pensamientos:

  • Mantener una instancia de cada clase en todo, una vez que encuentre que lo necesite. Luego, en lugar de CreateInstance, Clonarlo.
  • Una vez que haya creado la primera instancia, mantenga el tipo de instancia alrededor. a continuación, utilizar Activator.CreateInstance (Tipo)

caché la instancia para clonar o el Tipo en un Dictionary<string,Type> o Dictionary<string,object>.

+0

¿Se clona más rápido que crear una instancia desde un delegado en caché? No creo que lo sea, ¿entonces sería mejor guardar el contratista de la clase? ¿Sería esto un delegado? si se usó la reflexión para obtener el tipo y luego crear una instancia, ¿obtendría el contratista del tipo o instancia? Puede agregarse un código de muestra. Según entiendo, almacenar en caché el ctor de los tipos en un diccionario sería el más rápido. – Seabizkit

0

Defina e implemente una interfaz en lugar de utilizar la reflexión.

1

¡EXCELENTE! El enfoque de Class Factory parece ser el camino a seguir aquí.

Usando una combinación de Assembly.CreateInstance(typeNameString) en la primera solicitud, entonces la memoria caché Type en la fábrica.

En llamadas posteriores, use Activator.CreateInstance(type).

Usando este enfoque es un 20% más lento que usando un operador New nativo. No hay gran problema allí!

las estadísticas de la creación de 10 millones de Employee objetos de la siguiente manera:

  • 8 segundos utilizando el operador new

  • 10 segundos utilizando el tipo de enfoque de caché de fábrica//.

Aquí es el código de ejemplo, si alguien está interesado:

private IEmployee CachedClassFactory() 
{ 
    if(_typeCache == null) 
    { 
     // This is a one time hit to load the type into the cache 
     string typeName = "ClassFactoryTest.Employee"; 
     string assemblyName = "ClassFactoryTest"; 
     Assembly assembly = Assembly.Load(assemblyName); 
     IEmployee employee = assembly.CreateInstance(typeName) as IEmployee;       
     _typeCache = employee.GetType(); 
    } 

    IEmployee instance = Activator.CreateInstance(_typeCache) as IEmployee; 

    instance.FirstName = "Raiford"; 
    instance.LastName = "Brookshire"; 
    instance.Birthdate = DateTime.Now.AddYears(-35); 
    instance.Age = 35; 

    return instance;  
} 
+0

Creo que puede mejorar eso usando árboles de expresiones. Ver esto para un [ejemplo] (http://stackoverflow.com/questions/367577/why-does-the-c-sharp-compiler-emit-activator-createinstance-when-calling-new-in). – nawfal

+0

no estoy seguro de lo que está mostrando aquí en términos de redacción, ¿cómo sería un 20% más lento un valor en caché? – Seabizkit

Cuestiones relacionadas