Reflection mediante dynamic
Al Supporto Tecnico ci prepariamo in anticipo alle richieste sui prodotti attualmente in beta, i quali arriveranno nei prossimi mesi. Studiando Visual C# 2010 Beta 1 e le nuove feature introdotte nella runtime, ho notato che gli sviluppatori di applicazioni hanno a disposizione un nuova keyword, dynamic, che si basa sulla DLR, Dynamic Language Runtime.
Per la definizione formale e per come il compilatore si comporta durante la fase di compile-time vi rimando alla documentazione on-line che sicuramente esprime questi concetti teorici in modo più chiaro di quanto possa fare io.
Quel che m’interessa descrivere è l’impatto che questo nuovo costrutto ha sulla Reflection, in particolare su come si sia notevolmente semplificata la scrittura del codice. A tal fine ripercorriamo rapidamente come funzionava la reflection sino alla versione 3.5 della runtime.
Uno sviluppatore doveva interagire con la DLL che definisce il tipo interessato e successivamente invocare le funzioni implementate nella classe tramite InvokeMember. Questo rendeva la stesura del codice sicuramente più articolata di una normale invocazione di funzione, costringendo lo sviluppatore a distinguere tra le istanze realizzate mediante Reflection e le istanze “tradizionali”.
Vediamo di seguito il seguente codice che definisce la libreria ClassLibrary:
namespace ClassLibrary
{
public class MyMath
{
public long sum(int x, int y)
{
return x + y;
}
}
}
Ecco cosa accadeva nelle vecchie edizioni della runtime:
class Program
{
static void Main(string[] args)
{
Assembly myLibrary = null;
try
{
// Carico la Libreria interessata
myLibrary = Assembly.LoadFrom("C:\\ClassLibrary.dll");
// Reperisco la classe con cui interagire
Type MyMathType = myLibrary.GetType("ClassLibrary.MyMath");
// Creo un'istanza della classe tramite reflection
Object MyMathObj = Activator.CreateInstance(MyMathType);
// Preparo gli argomenti da passare alla funzione
Object[] methodArgs = new Object[2];
methodArgs[0] = 2;
methodArgs[1] = 3;
// Invoco il metodo sum indicando l'istanza, i parametri in ingresso ed i flag opportuni
Console.WriteLine("The sum of 3 + 2 is " +
MyMathType.InvokeMember("sum", BindingFlags.Default | BindingFlags.InvokeMethod,
null, MyMathObj, methodArgs).ToString());
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
Console.ReadLine();
}
}
Con i tipi dynamic la stesura di codice mediante la tecnica della reflection è praticamente identica all’invocazione di un metodo per una normale istanza:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
//Carico la dll interessata definendo un’istanza
dynamic test = Assembly.LoadFrom("C:\\ClassLibrary.dll").CreateInstance("ClassLibrary.MyMath");
// invoco il metodo tramite reflection, in modo del tutto trasperante
Console.WriteLine("La somma di 3+2 =" + test.sum(3, 2));
Console.ReadLine();
}
}
}
Non ci siamo notevolmente semplificati la vita?
Carmelo Pulvirenti
Support Engineer
Windows Mobile & Embedded Developer Support
.NET & Visual Studio Technology
Comments
Anonymous
September 19, 2009
Domanda, con dynamic potremo avere + problemi a runtime? CiaoAnonymous
September 20, 2009
Ciao Antonio, Grazie per la domanda. Nella fase di runtime non esistono rischi maggiori di quelli che si corrono con l’implementazione tradizionale della Reflection. In entrambi i casi, infatti, si potrà sollevare, in fase di runtime, un’eccezione dovuta la fatto che il metodo non è presente nelle classe indicata. Quindi vai tranquillo :-) Ciao, CarmeloAnonymous
September 22, 2009
Ciao, innanzi tutto complimenti per l' articolo e per il blog in generale! Non mi e' chiara una cosa: nell' esempio di sopra e' chiaro che voglio chiamare la funzione SUM. ma se la funzione da chiamare non e' nota a priori, tipo e' dentro una variabile come posso fare? in altre parole: e' possibile fare qalcosa di simile: string nomeMetodo = "sum"; test[nomeMetodo] (3, 2); Grazie!Anonymous
September 28, 2009
Ciao Stefano, L’utilizzo dei dynamic che ho presentato, consente al programmatore di non fare distinzione tra gli oggetti ottenuti mediante Reflection e quelli istanziati tradizionalmente. Per realizzare la funzionalità da te richiesta, dovrai utilizzare il metodo InvokeMember passando tra i parametri il nome del metodo da invocare. Come esempio puoi considerare la prima sezione di codice che ho scritto. Ciao, Carmelo.Anonymous
December 28, 2009
Ciao Carmelo, un'altra domanda sull'uso di questa splendida feature: a livello di risorse (complessità computazionale e memoria allocata) si ha un risparmio, un peggioramento o rimane tutto sostanzialmente uguale? penso ai casi in cui la reflection venga utilizzata in modo pesante ..Anonymous
February 03, 2010
Ciao Alberto, In generale invocare un metodo mediante la Reflection implica una riduzione delle perfomance di circa 7-8 volte rispetto un’invocazione “tradizionale”.Questo ovviamente è un risultato atteso per ovvie ragioni di compilazione. I dynamic non alterano le prestazioni del nostro software, ma ci facilitano la stesura delle nostre applicazioni. Saluti.