Generare codice sorgente da assembly .NET durante il debug
Articolo
Quando si esegue il debug di un'applicazione .NET, è possibile che si voglia visualizzare il codice sorgente non disponibile. Ad esempio, l'interruzione di un'eccezione o l'uso dello stack di chiamate per passare a un percorso di origine.
Nota
La generazione di codice sorgente (decompilazione) è disponibile solo per le applicazioni .NET ed è basata sul progetto open source ILSpy.
La decompilazione è disponibile solo in Visual Studio 2019 16.5 e versioni successive.
L'applicazione dell'attributo SuppressIldasmAttribute a un assembly o a un modulo impedisce a Visual Studio di tentare la decompilazione. Anche se l'attributo è obsoleto in .NET 6 e versioni successive, Visual Studio rispetta l'attributo .
Generare il codice sorgente
Quando si esegue il debug e non è disponibile alcun codice sorgente, Visual Studio visualizza il documento Origine non trovata oppure, se non sono presenti simboli per l'assembly, il documento Nessun simbolo caricato. Entrambi i documenti hanno un'opzione di Decompilazione del codice sorgente che genera codice C# per la posizione corrente. Il codice C# generato può quindi essere usato esattamente come qualsiasi altro codice sorgente. È possibile visualizzare il codice, controllare le variabili, impostare punti di interruzione e così via.
Nessun simbolo caricato
La figura seguente mostra il messaggio Nessun simbolo caricato.
Origine non trovata
La figura seguente mostra il messaggio di Origine non trovata.
Decompilazione automatica del codice
A partire da Visual Studio 2022 versione 17.7, il debugger di Visual Studio supporta la correzione automatica del codice .NET esterno. È possibile decompilare automaticamente quando si procede nel codice esterno o quando si usa la finestra dello stack delle chiamate.
Se si esegue un'istruzione nel codice implementato esternamente, il debugger lo decompila automaticamente e visualizza il punto di esecuzione corrente. Se si vuole eseguire l'istruzione nel codice esterno, disabilitare Just My Code.
È possibile decompilare dalla finestra Stack di chiamate senza disabilitare Just My Code.
Per decompilare automaticamente dalla finestra Call Stack:
Durante il debug con la finestra Stack di chiamate aperta, selezionare Mostra codice esterno.
Nella finestra Stack di chiamate fare doppio clic su qualsiasi frame dello stack. Il debugger decompila il codice e quindi passa direttamente al punto di esecuzione corrente.
Tutto il codice decompilato viene visualizzato anche nel nodo Origini esterne in Esplora soluzioni, semplificando l'esplorazione dei file esterni, se necessario.
È possibile eseguire il debug del codice decompilato e impostare punti di interruzione.
Per disabilitare la decompilazione automatica del codice esterno, andare su Strumenti > Opzioni > Debugging > Generale e deselezionare Decompila automaticamente all'origine quando necessario (solo per codice gestito).
Generare e incorporare origini per un assemblaggio
Oltre a generare codice sorgente per una posizione specifica, è possibile generare tutto il codice sorgente per un determinato assembly .NET. Per eseguire questa attività, passare alla finestra Moduli e, dal menu di scelta rapida di un assembly .NET, selezionare il comando Decompile Source to Symbol File. Visual Studio genera un file di simboli per l'assembly e quindi incorpora l'origine nel file di simboli. In un passaggio successivo è possibile estrarre il codice sorgente incorporato.
Estrarre e visualizzare il codice sorgente incorporato
È possibile estrarre i file di origine incorporati in un file di simboli usando il comando Estrai Codice Sorgente nel menu contestuale della finestra Moduli.
I file di origine estratti vengono aggiunti alla soluzione come file vari. La funzionalità file vari è disattivata per impostazione predefinita in Visual Studio. È possibile abilitare questa funzionalità dalla casella di controllo Strumenti>Opzioni>Ambiente>Documenti>Mostra file esterni in Esplora soluzioni. Se questa funzionalità non è abilitata, non è possibile aprire il codice sorgente estratto.
I file di origine estratti vengono visualizzati nei file vari nell'Esplora soluzioni .
La generazione di codice sorgente tramite la decompilazione è possibile solo quando il debugger è in modalità di interruzione e l'applicazione viene sospesa. Ad esempio, Visual Studio passa alla modalità di interruzione quando raggiunge un punto di interruzione o un'eccezione. È possibile attivare facilmente Visual Studio per interrompere la successiva esecuzione del codice usando il comando Interrompi tutto ().
Limitazioni di decompilazione
La generazione di codice sorgente dal formato intermedio (IL) usato negli assembly .NET presenta alcune limitazioni intrinseche. Di conseguenza, il codice sorgente generato non è simile al codice sorgente originale. La maggior parte delle differenze si trova nelle posizioni in cui le informazioni nel codice sorgente originale non sono necessarie in fase di esecuzione. Ad esempio, le informazioni come spazi vuoti, commenti e nomi delle variabili locali non sono necessarie in fase di esecuzione. È consigliabile usare l'origine generata per comprendere come il programma è in esecuzione e non come sostituzione del codice sorgente originale.
Eseguire il debug di assembly ottimizzati o di rilascio
Durante il debug del codice decompilato da un assembly compilato tramite ottimizzazioni del compilatore, potrebbero verificarsi i problemi seguenti:
I punti di interruzione potrebbero non essere sempre associati alla posizione di origine corrispondente.
L'avanzamento potrebbe non sempre spostarsi alla posizione corretta.
Le variabili locali potrebbero non avere nomi accurati.
Alcune variabili potrebbero non essere disponibili per la valutazione.
Una percentuale relativamente piccola di tentativi di decompilazione può causare un errore. Questo comportamento è dovuto a un errore di riferimento null del punto di sequenza in ILSpy. L'errore è stato risolto intercettando questi problemi ed eseguendo correttamente il tentativo di decompilazione.
I risultati della decompilazione dei moduli con modelli di codice asincroni/await possono essere incompleti o fallire completamente. L'implementazione ILSpy di async/await e yield state-machines è implementata solo parzialmente.
L'impostazione Just My Code (JMC) consente a Visual Studio di ignorare le chiamate del sistema, del framework, delle librerie e altre chiamate non utente. Durante una sessione di debug, la finestra Moduli mostra i moduli di codice che il debugger considera come Codice personale (codice utente).
La decompilazione dei moduli ottimizzati o di versione produce codice non utente. Se il debugger si interrompe nel codice non utente decompilato, ad esempio, viene visualizzata la finestra Nessuna origine. Per disabilitare Just My Code, passare a Tools>Options (o Debug>Options) >Debugging>Generale quindi deselezionare Enable Just My Code.
Fonti estratte
Il codice sorgente estratto da un assembly presenta le limitazioni seguenti:
Il nome e il percorso dei file generati non sono configurabili.
I file sono temporanei ed eliminati da Visual Studio.
I file vengono inseriti in una singola cartella e la gerarchia di cartelle che le fonti originali avevano non viene utilizzata.
Il nome del file per ogni file contiene un hash checksum del file.
Il codice generato è solo C#
La decompilazione genera solo file di codice sorgente in C#. Non esiste un'opzione per generare file in nessun'altra lingua.
Di seguito viene descritto come eseguire il debug di un'app .NET in modo efficiente usando Visual Studio Code per correggere rapidamente i bug. Usare il debugger interattivo in Visual Studio Code per analizzare e correggere le applicazioni C#.