La reflection è quello strumento che permette di interrogare a runtime i metadati di un assembly, analizzare i tipi, i membri ed invocare dinamicamente metodi, proprietà ed eventi. Il namespace System.Reflection c'è dal .NET Framework 1.0 e l'importanza di questo strumento si è fatta sempre più sentire, da una parte perché il framework è sempre più configurabile, dall'altra perché framework come NHibernate, Linq to SQL o Entity Framework lo pongono al centro di una questione importante: le performance.
Infatti la reflection è lenta. Tanto per dare un'idea con un semplice esempio, se dobbiamo creare un'istanza di una classe possiamo farlo chiamando il costruttore nel canonico modo oppure via reflection:
for (int x = 0; x < max; x++) p = new Product(); Type t = typeof(Product); for (int x = 0; x < max; x++) p = Activator.CreateInstance(t);
Sulla mia macchina, con 10milioni di iterazioni ottengo questi tempi:
00:00:00.1892963 00:00:01.8751132
Ci mette ben 10 volte di più. Per non parlare di come impostare le proprietà:
for (int x = 0; x < max; x++) p.Description = "ciao"; PropertyInfo pi = typeof(Product).GetProperty("Description", BindingFlags.Public | BindingFlags.Instance); for (int x = 0; x < max; x++) pi.SetValue(p, "ciao", null);
Escludendo i tempi di ricerca della proprietà con il metodo GetProperty, i dati sono:
00:00:00.1141661 00:00:16.4958957
Ovviamente questi sono dati indicativi ed è ovvio che il confronto con il codice compilato è ingiusto. Con la reflection abbiamo più dinamicità sui tipi e possiamo creare strumenti come gli ORM citati prima.
Come si possono quindi aumentare le performance? Una possibilità è quella di generare dinamicamente codice specifico per quel tipo e per certi membri. Infatti all'interno del namespace System.Reflection.Emit c'è tutto quello che serve per emettere IL al volo godendo delle stesse performance del codice compilato.
Una delle accuse che si fanno a NHibernate o LINQ to SQL è che sono lenti per via della reflection. In realtà, sia il primo (dalla versione v2) che il secondo, tolto il lavoro che fanno inizialmente di analisi delle classi e dei mapping, non usano reflection, ma a regime istanziano e impostano campi e proprietà con IL generato ad hoc. L'overhead semmai risiede nella gestione dei delegate e nel lavoro di mapping. In fondo se si pretende di lavorare indipendentemente dal database e instanziare tipi dinamicamente, non si può neanche pretendere di non pagare qualcosa per questa ulteriore stratificazione.
Comunque non è delle implementazioni degli ORM che mi interessa parlare, ma bensì di come generare codice IL. Lo mostrerò nel prossimo post dove farò vedere alcuni extension method che usano la System.Reflection.Emit e la classe LambaExpression per velocizzare le operazioni di reflection.
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
- Dettagli sul metodo SelectDTO, il 26 aprile 2009 alle 13:58
- LINQ to Reflection - Parte tre, il 20 aprile 2009 alle 07:08
- Abusi della parola chiave var e poca leggibilità dei generics, il 29 agosto 2008 alle 13:10
- Lambda Expression in Windows Presentation Foundation, il 7 agosto 2008 alle 18:49
- LINQ to reflection - Parte due, il 23 luglio 2008 alle 14:26
- Eccovi LINQ to reflection, il 19 luglio 2008 alle 21:17