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. Open-mouthed


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? Smile


Carmelo Pulvirenti
Support Engineer
Windows Mobile & Embedded Developer Support
.NET & Visual Studio Technology

Comments (6)

  1. Domanda, con dynamic potremo avere + problemi a runtime?

    Ciao

  2. carmelop says:

    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,

    Carmelo

  3. stefano manni says:

    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!

  4. carmelop says:

    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.

  5. Alberto Aggio says:

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

  6. carmelop says:

    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.