- Reflector .NET: un Visualizzatore Oggetti con disassembler -
 
COSA SERVE PER QUESTO TUTORIAL
Chiedi sul FORUM | Glossario cognizioni basiche di un qualsiasi linguaggio .Net
Come servirsi di Reflector .NET per apprendere e correggere

LE POTENZIALITÀ
Cos'è Reflector .NET e qual è la sua utilità.

In un precedente articolo abbiamo illustrato l'utilità e la potenza del Visualizzatore Oggetti di Visual Studio, oggi vogliamo invece presentare uno strumento simile ma infinitamente più potente: .NET Reflector. .NET Reflector è un software nato da Lutz Roeder e ora portato avanti dalla Red Gate che si comporta sostanzialmente come un disassemblatore di codice .Net. A partire da un qualsiasi assembly (libreria DLL o applicazione EXE) potrete quindi risalire al codice sorgente originale con un grado di fedeltà veramente eccezionale. Reflector, al contrario di ildasm, non si limita a mostrare il sorgente in Intermediate Langauge (MSIL, IL o ILAsm che lo si voglia chiamare) ma è in grado di convertirlo in tutti i principali (e grazie ai plugin anche in quelli secondari) linguaggi .Net: C#, VB.Net, Delphi, MC++ e così via. La visualizzazione è molto simile a quella del Visualizzatore Oggetti di Visual Studio ma mostra anche tutti i membri nascosti, privati e il loro rispettivo codice.
Servirsi di questo strumento è estremamente utile in molte occasioni, ad esempio per comprendere a fondo cosa fa una libreria di cui ci stiamo servendo (anche appartenente al framework .Net stesso) e nel caso anche ad individuarvi errori. Può però essere usato anche solo per comprendere come qualcun altro ha affrontato un problema e trarne vantaggio o per vedere come è stato generato il proprio codice, o come risulterebbe in altri linguaggi (sebbene per convertire codice ad esempio da C# a VB .Net esistano tool molto più adatti come SharpDevelop).

UN ESEMPIO DI UTILIZZO
Come si comporta in dettaglio il metodo Fill di OdbcDataAdapter.

Ammettiamo di doverci servire di un OdbcDataAdapter (classe utilizzata per effettuare query di selezione su database tramite ODBC) ma di non ricordare se è necessario aprire la connessione prima di chiamare il metodo Fill, o, se non necessario, si debba invece ricordarsi di chiuderla dopo la chiamata. Abbiamo tre modi di procedere per risolvere il problema: consultare la guida, provare del codice oppure andare a vedere come si comporta effettivamente il metodo OdbcDataAdapter.Fill. Tra le tre possibilità, l'ultima è certamente la più intrigante e quella che può arricchirci maggiormente (sebbene probabilmente non la più veloce).
Avviamo Reflector .NET e cerchiamo tra gli assembly già presenti System.Data, se non c'è, andiamo al menu File, Open Cache, e attendiamo il completo caricamento della lista di tutti gli assembly nella cache del sistema: nella casella per filtrare i risultati in alto digitiamo "Data" e selezioniamo System.Data. Nella schermata principale apparirà quindi l'assembly in questione, selezioniamolo e nel riquadro in basso troveremo informazioni come il nome, la locazione il tipo (libreria, applicazione console, applicazione Windows e così via). Espandendo il nodo troviamo il modulo che l'assembly contiene (System.Data.dll) e un'altra voce per le risorse che lasciamo esplorare al lettore. All'interno del modulo possiamo trovare un nodo contenente la lista di tutti gli assembly da cui System.Data dipende più tutti i namespace che contiene.
Espandiamo System.Data.Odbc ed individuiamo OdbcDataAdapter, al suo interno non possiamo però vedere il metodo Fill: ciò significa che esso coincide con quello della classe da cui eredita, espandiamo quindi la voce Base Types e troviamo System.Data.Common.DbDataAdapter, facciamo click destro, Go To Type Declaration. Ci troveremo così direttamente sulla classe in questione, espandiamo e scegliamo l'overload di Fill che ci interessa, ad esempio quello che prende come argomento una DataTable, facciamo click destro, Disassemble. Ed ecco nel riquadro di destra apparire il sorgente del metodo Fill in questione; possiamo ora scegliere dalla casella in alto il linguaggio da utilizzare che più preferiamo. Tuttavia nel sorgente non sembra esservi alcun riferimento ad apertura o chiusura di connessioni, ma vediamo che viene chiamato un altro overload di Fill, come in genere accade infatti gli overload secondari si riferiscono a quello principale che ha una definizione più ampia:

num = Me.Fill(dataTables, 0, 0, selectCommand, fillCommandBehavior)

Cliccando su Fill ci troveremo direttamente alla versione di Fill che ci interessa, ma anche qui vediamo una serie di controlli di scarso interesse e una chiamata ad un altro metodo, questa volta privato (altra pratica molto diffusa):

num = Me.FillInternal(Nothing, dataTables, startRecord, maxRecords, Nothing, command, behavior)

Clicchiamo su FillInternal e finalmente siamo giunti al cuore del metodo Fill e possiamo vedere chiamate ad un DataReader come ci si poteva aspettare; ma a parte questo ci sono due metodi di particolare interesse:


Dim open As ConnectionState = ConnectionState.Open
[...]
Try 
    DbDataAdapter.QuietOpen(connection, open)
    [...]
Finally
    DbDataAdapter.QuietClose(connection, open)
End Try

Ispezioniamo il metodo QuietOpen:


Private Shared Sub QuietOpen(ByVal connection As IDbConnection,  ByRef originalState As ConnectionState)
    originalState = connection.State
    If (originalState Is ConnectionState.Closed) Then
        connection.Open
    End If
End Sub

Se la connessione non è aperta la apre, altrimenti non fa nulla, se non impostare il parametro originalState (passato per riferimento) sullo stato iniziale.
Vediamo ora QuietClose:


Private Shared Sub QuietClose(ByVal connection As IDbConnection, ByVal originalState As ConnectionState)
    If ((Not connection Is Nothing) AndAlso (originalState = ConnectionState.Closed)) Then
        connection.Close
    End If
End Sub

Controlla semplicemente se la connessione esiste ancora e se originalState (la stessa variabile che era stata passata a QuietOpen) indica che la connessione era inizialmente chiusa, allora la riporta in quello stato, ovvero la chiude.
Possiamo quindi dedurre, che se chiamiamo Fill con la connessione aperta essa rimarrà tale, altrimenti verrà aperta e chiusa all'interno della stessa chiamata.

ALTRE FUNZIONI DI REFLECTOR
Altre funzionalità utili.

Tra le altre funzionalità Reflector permette di

  • effettuare ricerche tra metodi, proprietà e campi di tutte le classi caricate (anche se private al contrario di quanto fa il Visualizzatore Oggetti); menu View, Search;
  • individuare informazioni avanzate su una classe o un metodo come le classi e i metodi da cui dipende, da chi viene usata, da chi viene esposta e da chi viene istanziata; click destro sulla voce, Analyze;
  • avere il sorgente di una classe completa; click destro, Disassemble e in fondo al riquadro a destra cliccare su Expand Methods;

Esistono poi molti interessanti plugin che permettono di aggiungere linguaggi verso i quali è possibile disassemblare o addirittura creare un progetto utilizzabile in Visual Studio dell'assembly.

 

<< INDIETRO by VeNoM00