Architettura del visualizzatore
L'architettura di un visualizzatore del debugger è definita da due parti:
Il lato debugger viene eseguito all'interno del debugger di Visual Studio. Il codice del lato debugger crea e visualizza l'interfaccia utente del visualizzatore.
Il lato oggetto del debug viene eseguito all'interno del processo sottoposto a debug in Visual Studio (l'oggetto del debug).
Un visualizzatore è un componente del debugger che consente al debugger di visualizzare il contenuto di un oggetto dati in modo significativo e comprensibile. Alcuni visualizzatori supportano anche la modifica dell'oggetto dati. Scrivendo visualizzatori personalizzati, è possibile estendere il debugger in modo da gestire i tipi di dati personalizzati.
L'oggetto dati da visualizzare si trova all'interno del processo del quale si sta eseguendo il debug, ovvero il processo oggetto del debug. L'interfaccia utente in cui verranno visualizzati i dati viene creata all'interno del processo del debugger di Visual Studio:
Processo del debugger | Processo oggetto del debug |
---|---|
Interfaccia utente del debugger (Suggerimenti dati, Finestra Espressioni di controllo, Controllo immediato) | Oggetto dati da visualizzare |
Per visualizzare l'oggetto dati all'interno dell'interfaccia del debugger, è necessario del codice per stabilire la comunicazione tra i due processi. Di conseguenza, l'architettura del visualizzatore è costituita da due parti: il codice del lato debugger e il codice del lato oggetto del debug.
Il codice del lato debugger crea un'interfaccia utente che può essere richiamata dall'interfaccia del debugger, ad esempio una finestra Suggerimenti dati, Espressioni di controllo o Controllo immediato. L'interfaccia del visualizzatore viene creata utilizzando la classe DialogDebuggerVisualizer e l'interfaccia IDialogVisualizerService. Come tutte le API dei visualizzatori, DialogDebuggerVisualizer e IDialogVisualizerService si trovano nello spazio dei nomi Microsoft.VisualStudio.DebuggerVisualizers.
Lato debugger | Lato oggetto del debug |
---|---|
Classe DialogDebuggerVisualizer Interfaccia IDialogVisualizerService |
Oggetto dati |
L'interfaccia utente ottiene i dati da visualizzare da un provider di oggetti presente sul lato debugger:
Lato debugger | Lato oggetto del debug |
---|---|
Classe DialogDebuggerVisualizer Interfaccia IDialogVisualizerService |
Oggetto dati |
Provider di oggetti (implementa l'interfaccia IVisualizerObjectProvider) |
Sul lato oggetto del debug è presente un oggetto corrispondente denominato origine oggetto:
Lato debugger | Lato oggetto del debug |
---|---|
Classe DialogDebuggerVisualizer Interfaccia IDialogVisualizerService |
Oggetto dati |
Provider di oggetti (implementa l'interfaccia IVisualizerObjectProvider) | Origine oggetto (derivata dalla classe VisualizerObjectSource). |
Il provider di oggetti fornisce i dati dell'oggetto da visualizzare nell'interfaccia utente del visualizzatore, ottenendoli dall'origine oggetto. Il provider di oggetti e l'origine oggetto forniscono API per comunicare i dati degli oggetti tra il lato debugger e il lato debug.
Ogni visualizzatore deve ottenere l'oggetto dati da visualizzare. Nella tabella seguente sono indicate le API corrispondenti che il provider di oggetti e l'origine oggetto utilizzano per questo scopo:
Provider di oggetti | Origine oggetto |
---|---|
GetData -oppure- GetObject |
GetData |
Si tenga presente che il provider di oggetti può usare il metodo GetData o GetObject. Ciascuna API comporta una chiamata al metodo GetData nell'origine oggetto. Una chiamata al metodo Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource.GetData consente di compilare un oggetto System.IO.Stream che rappresenta una forma serializzata dell'oggetto che si sta visualizzando.
Microsoft.VisualStudio.DebuggerVisualizers.IVisualizerObjectProvider.GetObject deserializza nuovamente i dati nel formato dell'oggetto, che può quindi essere visualizzato nell'interfaccia utente creata con DialogDebuggerVisualizer. Microsoft.VisualStudio.DebuggerVisualizers.IVisualizerObjectProvider.GetData compila i dati sotto forma di oggetto Stream
non elaborato, che deve essere deserializzato dall'utente. Microsoft.VisualStudio.DebuggerVisualizers.IVisualizerObjectProvider.GetObject funziona chiamando Microsoft.VisualStudio.DebuggerVisualizers.IVisualizerObjectProvider.GetData per ottenere l'oggetto Stream
serializzato, quindi deserializzando i dati. Usare il metodo Microsoft.VisualStudio.DebuggerVisualizers.IVisualizerObjectProvider.GetData quando l'oggetto non è serializzabile con .NET e non richiede la serializzazione personalizzata. In tal caso è necessario eseguire anche l'override del metodo Microsoft.VisualStudio.DebuggerVisualizers.VisualizerObjectSource.Serialize.
Se si sta creando un visualizzatore di sola lettura, è sufficiente una comunicazione unidirezionale con il metodo GetData o GetObject. Se si sta creando un visualizzatore che supporta la modifica di oggetti dati, sono necessarie altre funzionalità. È anche necessario poter inviare un oggetto dati dal provider di oggetti nuovamente all'origine oggetto. Nella tabella seguente sono indicate le API del provider di oggetti e dell'origine oggetto utilizzate per questo scopo:
Provider di oggetti | Origine oggetto |
---|---|
ReplaceData -oppure- ReplaceObject |
CreateReplacementObject |
Si tenga presente che il provider di oggetti può usare due API. I dati vengono sempre inviati dal provider di oggetti all'origine oggetto come oggetto Stream
, ma il metodo ReplaceData richiede la serializzazione dell'oggetto in un oggetto Stream
.
Il metodo ReplaceObject accetta l'oggetto specificato, lo serializza in un oggetto Stream
, quindi chiama il metodo ReplaceData per inviare l'oggetto Stream
al metodo CreateReplacementObject.
L'utilizzo di uno dei metodi di sostituzione consente di creare un oggetto dati nuovo nel lato oggetto del debug che sostituisce l'oggetto visualizzato. Se si desidera modificare il contenuto dell'oggetto originale senza sostituirlo, utilizzare uno dei metodi di trasferimento illustrati nella tabella seguente. Queste API trasferiscono contemporaneamente i dati in entrambe le direzioni, senza sostituire l'oggetto visualizzato:
Provider di oggetti | Origine oggetto |
---|---|
TransferData -oppure- TransferObject |
TransferData |