2009-07-30 9 views
7

teniendo en cuenta que los datos bastante estáticos no se deben volver a evaluar sino que se almacenan en caché, me pregunté si es posible utilizar Reflection para obtener propiedades de clase una vez y luego almacenarlas en caché para poder evaluar dinámicamente propiedades del objeto y leer/asignar valores, pero no tener la sobrecarga de reflexión cada vez que hago eso. ¿Es esto posible (código de muestra?)?Resultados de reflexión de caché (propiedades de clase)

Para aclarar un poco, digamos que tengo esta clase:

public class Cloud 
{ 
    Boolean IsWhite; 
} 

y yo estoy tratando de hacer ahora un método que me permite hacer algo como esto (pseudocódigo):

Update(myCloudInstance, new {IsWhite, true}); 

La actualización debería verificar primero con la memoria caché si ya conoce las propiedades de Cloud (typeof (myCloudInstance)) y luego usar la información almacenada para asignar la propiedad "IsWhite" al valor "true" en lugar de hacer Reflection nuevamente.

¿Alguna idea sobre cómo hacer esto?

Respuesta

7

No está claro exactamente lo que estás haciendo, pero el almacenamiento en caché definitivamente puede marcar la diferencia con la reflexión.

En particular, si usted está invocando métodos (o getters/setters de propiedad) y puede hacerlo en una forma de tipo seguro en lo que se refiere al código de llamada, que can make a huge difference si convierte el MethodInfo en un strongly- escribió delegado una vez y luego reutilizó eso.

Si pudiera darnos un ejemplo completo de lo que está tratando de hacer, eso nos ayudaría a pensar en ideas más específicas o incluso en el código. Si solo va a almacenar en caché un PropertyInfo que puede no tener tanto (o ningún) efecto, es posible que los métodos normales Type.GetProperty (etc.) ya sean bastante rápidos. Como siempre con las preguntas de rendimiento, la clave es medir lo que estás haciendo en realidad. Realice un cambio y vuelva a medir, etc.

+0

Su respuesta me indicó en la dirección correcta (cómo almacenar PropertyInfo) que es en realidad más rápido que GetProperty (aún no ha llegado el momento, pero la capacidad de respuesta de mi página parece mejorada) – Alex

+0

Si puede caché delegados llamar a la propiedad en un tipo seguro, que bien puede hacer que sea más rápido de nuevo. Definitivamente tiempo, aunque ... –

2

No es necesario que el costo de la reflexión sea tan grande como cree. Además de los delegados (que Jon discute) también se puede usar cosas como HyperDescriptor para minimizar el costo de la reflexión sin cambiar el código mucho más - se convierte simplemente en PropertyDescriptor lugar:

PropertyDescriptorCollection props = TypeDescriptor.GetProperties(myCloudInstance); 
// ideally cache props, but not essential 

continuación

object val = props["IsWhite"].GetValue(myCloudInstance); 

o si lo usa mucho, considere almacenar el PropertyDescriptor en algún lugar, también.

Sin embargo ... como Jon, ¡realmente no estoy 100% seguro de lo que estás tratando de hacer!

0

El montaje dinámico debería ayudar con la preocupación sobre el rendimiento de la reflexión. Alguien ha implementado evaluadores de propiedades usando el ensamblaje dinámico here.

1

Creo que la mejor manera de hacerlo es conseguir que el método captador o, convertirlo a un delegado, y trabajar con el delegado, no hay manera más rápida:

PropertyInfo propertyInfoProperty1 = type.GetType().GetProperty("Property1"); 
Func<TYPE, string> get_Property1 = (Func<TYPE, string>)Delegate.CreateDelegate(typeof(Func<TYPE, string>), propertyInfoProperty1.GetGetMethod()); 

luego llamar al captador método:

string value = get_Property1(type); 

puede almacenar en caché los delegados.

2

Creé una tabla hash para almacenar en caché los resultados de la reflexión. La primera vez, es necesario hacer una llamada a GetProperties y almacenar los resultados en el hastable. Los próximos tiempos, primero verifique la tabla hash para los objetos List of PropertyInfo. Si existe, úselo. Si no, invoque GetProperties.

Utilizo esto para asignar un lector de datos a una lista de entidades.

Mi implementación se basa en: A Defense on Reflection in .Net, por Nick Harrison (http://www.simple-talk.com/dotnet/.net-framework/a-defense-of-reflection-in-.net/).

Por lo tanto, ahí está:

public class MapeadorDataReaderListaObjetos 
{ 

    private Hashtable properties; 

    private Hashtable Properties 
    { 
     get 
     { 
      if (properties == null) 
       properties = new Hashtable(); 
      return properties; 
     } 
     set { properties = value; } 
    } 

    private void LoadProperties(object targetObject, Type targetType) 
    { 
     var flags = BindingFlags.DeclaredOnly| BindingFlags.Instance| BindingFlags.Public; 

     if (properties == null) 
     { 
      List<PropertyInfo> propertyList = new List<PropertyInfo>(); 
      PropertyInfo[] objectProperties = targetType.GetProperties(flags); 
      foreach (PropertyInfo currentProperty in objectProperties) 
      { 
       propertyList.Add(currentProperty); 
      } 
      properties = new Hashtable(); 
      properties[targetType.FullName] = propertyList; 
     } 

     if (properties[targetType.FullName] == null) 
     { 
      List<PropertyInfo> propertyList = new List<PropertyInfo>(); 
      PropertyInfo[] objectProperties = targetType.GetProperties(flags); 
      foreach (PropertyInfo currentProperty in objectProperties) 
      { 
       propertyList.Add(currentProperty); 
      } 
      properties[targetType.FullName] = propertyList; 
     } 
    } 

    public void MapearDataReaderListaObjetos <T> (IDataReader dr, List<T> lista) where T: new() 
    { 
     Type businessEntityType = typeof(T); 
     List<T> entitys = new List<T>(); 
     T miObjeto = new T(); 
     LoadProperties(miObjeto, businessEntityType); 
     List<PropertyInfo> sourcePoperties = Properties[businessEntityType.FullName] as List<PropertyInfo>; 

     while (dr.Read()) 
     { 
      T newObject = new T(); 
      for (int index = 0; index < dr.FieldCount; index++) 
      { 
       for (int _indice = 0; _indice < sourcePoperties.Count; _indice++) 
       { 
        if (sourcePoperties[_indice].Name.ToUpper() == dr.GetName(index).ToUpper()); 
        { 
         string _tipoProp = sourcePoperties[_indice].PropertyType.ToString(); 
         PropertyInfo info = sourcePoperties[_indice] as PropertyInfo; 
         if ((info != null) && info.CanWrite) 
         { 
          info.SetValue(newObject, dr.GetValue(index), null); 
         } 
        } 
       } 
      } 
      entitys.Add(newObject); 
     } 
     dr.Close(); 
     lista = entitys; 
    } 
} 

Entonces, lo llamo de mi DataAcces capa, de esta manera:

public List <Entities.ENFactura> ListaxIdFactura (SqlTransaction Tr, Entities.ENFactura oBEFactura) 
{ 

    SqlConnection Cn = new SqlConnection(); 
    Cn = _Connection.ConexionSEG(); 

    List<Entities.ENFactura> loBEFactura = new List<Entities.ENFactura>(); 

    using (Cn) 
    { 
     Cn.Open(); 
     SqlDataReader drd = (odaSQL.fSelDrd(Cn, Tr, "Pa_CC_Factura_Listar_x_IdProveedor", oBEFactura)); 
     if (drd != null) 
     { 
      if (drd.HasRows) 
      { 
       mapeador.MapearDataReaderListaObjetos <ENFactura>(drd, loBEFactura); 
      } 
     } 
    } 
    return (loBEFactura); 
} 

Así, de esta manera, el DAL consigue un datareader, trazarlo a una lista de entidades comerciales y devuélvala a la Capa lógica de negocios.

Esta clase (MapeadorDataReaderListaObjetos) tiene algunos problemas todavía, sobre todo en:

info.SetValue(newObject, _valor, null); 

newObject y _valor deben ser del mismo tipo o obtendrá una excepción (conversión de System.Int64 a System.Int32, en caso de que la propiedad de su entidad sea Int32 y su campo correspondiente en la tabla de la base de datos sea bigint, por ejemplo).

Además, si una propiedad de entidad es otra entidad, esto no funcionará, porque los lectores de datos no devuelven objetos de entidad.

Obviamente, esto se puede mejorar.

En cuanto a la reflexión y los delegados, encontré este artículo: Reflexión: ¿lenta o rápida? Demostración con soluciones, por Abhishek Sur, en http://www.abhisheksur.com/2010/11/reflection-slow-or-faster-demonstration.html

Otro buen artículo es: Rendimiento trampas de Dodge Common Craft Aplicaciones Speedy, por Joel POBAR, en http://msdn.microsoft.com/en-us/magazine/cc163759.aspx.

Espero que esto ayude.

Cuestiones relacionadas