2009-07-30 22 views
7

considerando che i dati piuttosto statici non devono essere rivalutati ma memorizzati nella cache, mi chiedevo se è possibile utilizzare Reflection per ottenere le proprietà di classe una volta e quindi memorizzarle nella cache in modo da poter valutare dinamicamente Proprietà dell'oggetto e leggi/assegna valori, ma non ha il sovraccarico di Reflection ogni volta che lo faccio. È possibile (codice di esempio?)?Risultati riflessione cache (proprietà classe)

Per chiarire un po ', Diciamo che ho questa classe:

public class Cloud 
{ 
    Boolean IsWhite; 
} 

e sto cercando di fare ora un metodo che mi permette di fare qualcosa di simile a questo (pseudocodice):

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

L'aggiornamento dovrebbe verificare prima con la cache se conosce già le proprietà di Cloud (typeof (myCloudInstance)), quindi utilizzare le informazioni memorizzate nella cache per assegnare la proprietà "IsWhite" al valore "true" invece di fare nuovamente Reflection.

Qualche idea su come fare questo?

risposta

7

Non è chiaro esattamente quello che stai facendo, ma il caching può certamente fare la differenza con la riflessione.

In particolare, se si sta invocando metodi (o getter/setter di proprietà) e può farlo in un modo type-safe per quanto riguarda il codice chiamante è interessato, can make a huge difference se si converte il MethodInfo in uno strongly- digitato delegato una volta e poi riutilizzare quello.

Se potessi fornirci un esempio completo di ciò che stai cercando di fare, questo ci aiuterebbe a proporre idee più specifiche o addirittura codice. Se stai solo andando a mettere in cache un PropertyInfo che potrebbe non avere lo stesso (o nessun effetto) - è possibile che i normali metodi Type.GetProperty (ecc.) Siano già piuttosto veloci. Come sempre con domande sulle prestazioni, la chiave è misurare ciò che stai effettivamente facendo. Apporta una modifica e misura nuovamente, ecc.

+0

La tua risposta mi ha suggerito nella giusta direzione (come memorizzare PropertyInfo) che è in realtà più veloce di GetProperty (non l'ha ancora programmato, ma la reattività della mia pagina sembra migliorata.) – Alex

+0

Se è possibile memorizzare nella cache i delegati per chiamare la proprietà in un sicuro dal punto di vista del tipo, questo potrebbe renderlo nuovamente più veloce. Decisamente il tempo però ... –

2

Il costo della riflessione non deve essere grande come pensi. Oltre ai delegati (che Jon discute) è anche possibile utilizzare le cose come HyperDescriptor per ridurre al minimo i costi di riflessione senza modificare il codice molto - diventa semplicemente PropertyDescriptor invece:

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

poi

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

o se lo si utilizza molto, si consideri di memorizzare anche lo PropertyDescriptor.

Tuttavia ... come Jon, non sono sicuro al 100% di quello che stai cercando di fare!

0

L'assemblaggio dinamico dovrebbe aiutare con la preoccupazione per le prestazioni di riflessione. Qualcuno ha implementato i valutatori di proprietà usando l'assemblaggio dinamico here.

1

Penso che il modo migliore per farlo è quello di ottenere il metodo getter o setter, convertirlo in un delegato, e di lavorare con il delegato, non c'è modo più veloce:

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

quindi chiamare il getter metodo:

string value = get_Property1(type); 

È possibile memorizzare nella cache i delegati.

2

Ho creato una tabella hash per memorizzare nella cache i risultati della riflessione. La prima volta, è necessario effettuare una chiamata a GetProperties e archiviare i risultati nella hastable. Le volte successive, prima controlla la tabella hash per l'elenco di oggetti PropertyInfo. Se esiste, usalo. In caso contrario, richiamare GetProperties.

Lo uso per associare un datareader a un elenco di entità.

La mia implementazione è basata su: A Defense on Reflection in .Net, di Nick Harrison (http://www.simple-talk.com/dotnet/.net-framework/a-defense-of-reflection-in-.net/).

Quindi, non v'è:

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; 
    } 
} 

Poi, io lo chiamo dal mio DataAcces strato, in questo modo:

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); 
} 

Quindi, in questo modo, il DAL ottiene un datareader, mapparlo a un elenco di entità aziendali e restituirlo al livello di business logic.

Questa classe (MapeadorDataReaderListaObjetos) ha alcuni problemi ancora, in particolare a:

info.SetValue(newObject, _valor, null); 

newObject e _valor deve essere dello stesso tipo o avrai un'eccezione (conversione da System.Int64 a System.Int32, nel caso in cui la proprietà dell'entità sia Int32 e il suo campo corrispondente nella tabella del database sia bigint, ad esempio).

Inoltre, se una proprietà di entità è un'altra entità, ciò non funzionerà, poiché i datareader non restituiscono oggetti di entità.

Ovviamente, questo può essere migliorato.

Riguardo a riflessione e delegati, ho trovato questo articolo: Reflection - Slow or Fast? Dimostrazione con le soluzioni, di Abhishek Sur, a http://www.abhisheksur.com/2010/11/reflection-slow-or-faster-demonstration.html

Un altro buon articolo è: Dodge Comune performance Insidie ​​da Craft Applicazioni Speedy, da Joel Pobar, a http://msdn.microsoft.com/en-us/magazine/cc163759.aspx.

Spero che questo aiuti.

Problemi correlati