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.
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
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ò ... –