Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Vizualizéry ladicího programu jsou funkce sady Visual Studio, která poskytuje vlastní vizualizaci proměnných nebo objektů konkrétního typu .NET během ladicí relace.
Vizualizéry ladicího programu jsou přístupné z datového tipu , který se zobrazí při najetí myší na proměnnou nebo z oken Automatické hodnoty, Místní hodnoty a Kukátku :
Začínáme
Postupujte podle oddílu Vytvořit projekt rozšíření v části Začínáme.
Pak přidejte třídu rozšiřující DebuggerVisualizerProvider a použijte na ni atribut VisualStudioContribution.
/// <summary>
/// Debugger visualizer provider class for <see cref="System.String"/>.
/// </summary>
[VisualStudioContribution]
internal class StringDebuggerVisualizerProvider : DebuggerVisualizerProvider
{
/// <summary>
/// Initializes a new instance of the <see cref="StringDebuggerVisualizerProvider"/> class.
/// </summary>
/// <param name="extension">Extension instance.</param>
/// <param name="extensibility">Extensibility object.</param>
public StringDebuggerVisualizerProvider(StringDebuggerVisualizerExtension extension, VisualStudioExtensibility extensibility)
: base(extension, extensibility)
{
}
/// <inheritdoc/>
public override DebuggerVisualizerProviderConfiguration DebuggerVisualizerProviderConfiguration => new("My string visualizer", typeof(string));
/// <inheritdoc/>
public override async Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
{
string targetObjectValue = await visualizerTarget.ObjectSource.RequestDataAsync<string>(jsonSerializer: null, cancellationToken);
return new MyStringVisualizerControl(targetObjectValue);
}
}
Předchozí kód definuje nový vizualizér ladicího programu, který se vztahuje na objekty typu string:
- Vlastnost
DebuggerVisualizerProviderConfigurationdefinuje zobrazovaný název vizualizéru a podporovaný typ .NET. - Metoda
CreateVisualizerAsyncje vyvolána Visual Studio, když uživatel požádá o zobrazení vizualizéru pro určitou hodnotu.CreateVisualizerAsyncpomocí objektuVisualizerTargetnačte hodnotu, která se má vizualizovat, a předá ji vlastnímu vzdálenému uživatelskému ovládacímu prvku (odkaz na dokumentaci k vzdálenému uživatelskému rozhraní ). Vzdálený uživatelský ovládací prvek se pak vrátí a zobrazí se v automaticky otevírané okně v sadě Visual Studio.
Cílení na více typů
Vlastnost konfigurace umožňuje vizualizéru cílit na více typů, pokud je to vhodné. Dokonalým příkladem je Vizualizér datové sady, který podporuje vizualizaci DataSetobjektů , DataTableDataView, a DataViewManager objektů. Tato funkce usnadňuje vývoj rozšíření, protože podobné typy můžou sdílet stejné uživatelské rozhraní, zobrazit modely a zdroj objektů vizualizéru.
/// <inheritdoc/>
public override DebuggerVisualizerProviderConfiguration DebuggerVisualizerProviderConfiguration => new DebuggerVisualizerProviderConfiguration(
new VisualizerTargetType("DataSet Visualizer", typeof(System.Data.DataSet)),
new VisualizerTargetType("DataTable Visualizer", typeof(System.Data.DataTable)),
new VisualizerTargetType("DataView Visualizer", typeof(System.Data.DataView)),
new VisualizerTargetType("DataViewManager Visualizer", typeof(System.Data.DataViewManager)));
/// <inheritdoc/>
public override async Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
{
...
}
Zdroj objektu vizualizéru
Zdroj objektu vizualizéru je třída .NET, která je načtena ladicím programem v procesu ladění. Vizualizér ladicího programu může načíst data ze zdroje objektu vizualizéru pomocí metod vystavených metodou VisualizerTarget.ObjectSource.
Výchozí zdroj objektu vizualizéru umožňuje vizualizérům ladicího programu načíst hodnotu objektu, která se má vizualizovat voláním RequestDataAsync<T>(JsonSerializer?, CancellationToken) metody. Výchozí zdroj objektu vizualizéru používá k serializaci hodnoty Newtonsoft.Json a knihovny VisualStudio.Extensibility také pro deserializaci používají Newtonsoft.Json. Alternativně můžete použít RequestDataAsync(CancellationToken) k načtení serializované hodnoty jako JToken.
Pokud chcete vizualizovat typ .NET, který je nativně podporován Newtonsoft.Json, nebo chcete vizualizovat vlastní typ a můžete ho serializovat, předchozí pokyny stačí k vytvoření jednoduchého vizualizéru ladicího programu. Přečtěte si, jestli chcete podporovat složitější typy nebo používat pokročilejší funkce.
Použití vlastního zdroje objektů vizualizéru
Pokud typ, který chcete vizualizovat, nelze automaticky serializovat pomocí Newtonsoft.Json, můžete vytvořit vlastní zdroj vizualizéru objektu pro zpracování serializace.
- Vytvořte nový projekt knihovny tříd .NET, který cílí na
netstandard2.0. V případě potřeby se můžete zaměřit na konkrétnější verzi rozhraní .NET Framework nebo .NET (napříkladnet472nebonet6.0), aby bylo možno serializovat objekt, který chcete vizualizovat. - Přidejte odkaz na balíček verze
DebuggerVisualizers17.6 nebo novější. - Přidejte třídu, která rozšiřuje
VisualizerObjectSource, a přepišteGetData, který zapisuje serializovanou hodnotutargetdo prouduoutgoingData.
public class MyObjectSource : VisualizerObjectSource
{
/// <inheritdoc/>
public override void GetData(object target, Stream outgoingData)
{
MySerializableType result = Convert(match);
SerializeAsJson(outgoingData, result);
}
private static MySerializableType Convert(object target)
{
// Add your code here to convert target into a type serializable by Newtonsoft.Json
...
}
}
Použití vlastní serializace
Tuto metodu VisualizerObjectSource.SerializeAsJson můžete použít k serializaci objektu pomocí Newtonsoft.Json na objekt Stream bez přidání odkazu na Newtonsoft.Json do knihovny. Vyvoláním SerializeAsJson se prostřednictvím reflexe načte verze sestavení Newtonsoft.Json do procesu, který se ladí.
Pokud potřebujete odkazovat na Newtonsoft.Json, měli byste použít stejnou verzi, na kterou odkazuje Microsoft.VisualStudio.Extensibility.Sdk balíček, ale je vhodnější použít DataContract a DataMember atributy pro podporu serializace objektů místo toho, abyste se museli spoléhat na typy Newtonsoft.Json.
Alternativně můžete implementovat vlastní serializaci (například binární serializaci) přímo zapisovat do outgoingData.
Přidání knihovny DLL zdrojového objektu vizualizéru do rozšíření
Upravte soubor s příponou .csproj přidáním ProjectReference do projektu zdrojové knihovny objektu vizualizéru, což zajistí, že zdrojová knihovna objektu vizualizéru bude zkompilována před zabalením rozšíření.
Přidejte také položku Content včetně knihovny DLL zdrojového objektu vizualizéru do podsložky netstandard2.0 rozšíření.
<ItemGroup>
<Content Include="pathToTheObjectSourceDllBinPath\$(Configuration)\netstandard2.0\MyObjectSourceLibrary.dll" Link="netstandard2.0\MyObjectSourceLibrary.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MyObjectSourceLibrary\MyObjectSourceLibrary.csproj" />
</ItemGroup>
Alternativně můžete použít podsložky net4.6.2 nebo netcoreapp, pokud jste vytvořili zdrojové knihovny vizualizéru, které jsou cílené na rozhraní .NET Framework nebo .NET. Můžete dokonce zahrnout všechny tři podsložky s různými verzemi zdrojové knihovny vizualizéru objektů, ale je lepší cílit pouze na netstandard2.0.
Měli byste se pokusit minimalizovat počet závislostí knihovny DLL zdrojové knihovny vizualizéru objektů. Pokud má zdrojová knihovna vizualizéru jiné závislosti než Microsoft.VisualStudio.DebuggerVisualizers a knihovny, které jsou již automaticky načteny v procesu ladění, nezapomeňte tyto soubory DLL přidat do stejné podsložky jako knihovnu DLL zdrojového vizualizéru objektu.
Aktualizujte poskytovatele vizualizace ladicího programu tak, aby používal vlastní zdroj objektu vizualizéru
Potom můžete aktualizovat DebuggerVisualizerProvider konfiguraci tak, aby odkazovala na zdroj objektu vlastního vizualizéru:
public override DebuggerVisualizerProviderConfiguration DebuggerVisualizerProviderConfiguration => new("My visualizer", typeof(TypeToVisualize))
{
VisualizerObjectSourceType = new(typeof(MyObjectSource)),
};
public override async Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
{
MySerializableType result = await visualizerTarget.ObjectSource.RequestDataAsync<MySerializableType>(jsonSerializer: null, cancellationToken);
return new MyVisualizerUserControl(result);
}
Práce s velkými a složitými objekty
Pokud načtení dat ze zdroje objektu vizualizéru nejde provést s jediným voláním RequestDataAsyncbez parametrů , můžete místo toho provést složitější výměnu zpráv se zdrojem vizualizéru objektu tak, že několikrát vyvoláte RequestDataAsync<TMessage, TResponse>(TMessage, JsonSerializer?, CancellationToken) a odešlete různé zprávy do zdroje vizualizéru objektu. Zprávu i odpověď serializuje infrastruktura VisualStudio.Extensibility pomocí Newtonsoft.Json. Další přepsání RequestDataAsync umožňují používat JToken objekty nebo implementovat vlastní serializaci a deserializaci.
Pomocí různých zpráv můžete implementovat libovolný vlastní protokol, který načte informace ze zdroje vizualizéru objektů. Nejběžnějším případem použití této funkce je rozdělení načítání potenciálně velkého objektu na několik volání pro zabránění vypršení časového limitu.
Toto je příklad, jak můžete načíst obsah potenciálně velké kolekce po jedné položce:
for (int i = 0; ; i++)
{
MySerializableType? collectionEntry = await visualizerTarget.ObjectSource.RequestDataAsync<int, MySerializableType?>(i, jsonSerializer: null, cancellationToken);
if (collectionEntry is null)
{
break;
}
observableCollection.Add(collectionEntry);
}
Výše uvedený kód používá jednoduchý index jako zprávu pro RequestDataAsync volání. Odpovídající zdrojový kód vizualizéru by přepsal metodu TransferData (místo GetData):
public class MyCollectionTypeObjectSource : VisualizerObjectSource
{
public override void TransferData(object target, Stream incomingData, Stream outgoingData)
{
var index = (int)DeserializeFromJson(incomingData, typeof(int))!;
if (target is MyCollectionType collection && index < collection.Count)
{
var result = Convert(collection[index]);
SerializeAsJson(outgoingData, result);
}
else
{
SerializeAsJson(outgoingData, null);
}
}
private static MySerializableType Convert(object target)
{
// Add your code here to convert target into a type serializable by Newtonsoft.Json
...
}
}
Výše uvedený zdroj vizualizéru využívá metodu VisualizerObjectSource.DeserializeFromJson k deserializaci zprávy odeslané poskytovatelem vizualizéru z incomingData.
Při implementaci poskytovatele vizualizéru ladicího programu, který provádí složitou interakci se zdrojem vizualizérového objektu, je obvykle lepší předat VisualizerTarget vizualizéru RemoteUserControl, aby mohlo dojít k asynchronní výměně zpráv při načítání ovládacího prvku. Odesílání zpráv do zdroje objektu vizualizéru pomocí VisualizerTarget vám umožňuje načítat data na základě interakcí uživatele s uživatelským rozhraním vizualizéru.
public override Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
{
return Task.FromResult<IRemoteUserControl>(new MyVisualizerUserControl(visualizerTarget));
}
internal class MyVisualizerUserControl : RemoteUserControl
{
private readonly VisualizerTarget visualizerTarget;
public MyVisualizerUserControl(VisualizerTarget visualizerTarget)
: base(new MyDataContext())
{
this.visualizerTarget = visualizerTarget;
}
public override async Task ControlLoadedAsync(CancellationToken cancellationToken)
{
// Start querying the VisualizerTarget here
...
}
...
Otevírání vizualizérů jako nástrojová okna
Ve výchozím nastavení se všechna rozšíření vizualizéru ladicího programu otevírají jako modální dialogová okna v popředí sady Visual Studio. Proto pokud chce uživatel pokračovat v interakci s integrovaným vývojovém prostředím ( IDE), musí být vizualizér zavřený. Pokud je však vlastnost Style nastavena na ToolWindow v vlastnosti DebuggerVisualizerProviderConfiguration, bude vizualizér otevřen jako nemodální okno nástroje, které může zůstat otevřené po celou dobu ladicí relace. Pokud není deklarován žádný styl, použije se výchozí hodnota ModalDialog .
public override DebuggerVisualizerProviderConfiguration DebuggerVisualizerProviderConfiguration => new("My visualizer", typeof(TypeToVisualize))
{
Style = VisualizerStyle.ToolWindow
};
public override async Task<IRemoteUserControl> CreateVisualizerAsync(VisualizerTarget visualizerTarget, CancellationToken cancellationToken)
{
// The control will be in charge of calling the RequestDataAsync method from the visualizer object source and disposing of the visualizer target.
return new MyVisualizerUserControl(visualizerTarget);
}
Kdykoli se vizualizér rozhodne být otevřen jako ToolWindow, bude se muset přihlásit k události StateChanged z VisualizerTarget. Když je vizualizér otevřen jako okno nástroje, nebrání uživateli v obnovení ladicí relace. Tato výše zmíněná událost se tedy vyvolá debuggerem pokaždé, když dojde ke změně stavu cíle ladění. Autoři rozšíření Vizualizéru by měli věnovat zvláštní pozornost těmto oznámením, protože cíl vizualizátoru je k dispozici pouze tehdy, když je aktivní ladicí relace a cíl ladění je pozastaven. Pokud cíl vizualizéru není k dispozici, volání metod ObjectSource selže s chybou VisualizerTargetUnavailableException.
internal class MyVisualizerUserControl : RemoteUserControl
{
private readonly VisualizerDataContext dataContext;
#pragma warning disable CA2000 // Dispose objects before losing scope
public MyVisualizerUserControl(VisualizerTarget visualizerTarget)
: base(dataContext: new VisualizerDataContext(visualizerTarget))
#pragma warning restore CA2000 // Dispose objects before losing scope
{
this.dataContext = (VisualizerDataContext)this.DataContext!;
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
this.dataContext.Dispose();
}
}
[DataContract]
private class VisualizerDataContext : NotifyPropertyChangedObject, IDisposable
{
private readonly VisualizerTarget visualizerTarget;
private MySerializableType? _value;
public VisualizerDataContext(VisualizerTarget visualizerTarget)
{
this.visualizerTarget = visualizerTarget;
visualizerTarget.StateChanged += this.OnStateChangedAsync;
}
[DataMember]
public MySerializableType? Value
{
get => this._value;
set => this.SetProperty(ref this._value, value);
}
public void Dispose()
{
this.visualizerTarget.Dispose();
}
private async Task OnStateChangedAsync(object? sender, VisualizerTargetStateNotification args)
{
switch (args)
{
case VisualizerTargetStateNotification.Available:
case VisualizerTargetStateNotification.ValueUpdated:
Value = await visualizerTarget.ObjectSource.RequestDataAsync<MySerializableType>(jsonSerializer: null, CancellationToken.None);
break;
case VisualizerTargetStateNotification.Unavailable:
Value = null;
break;
default:
throw new NotSupportedException("Unexpected visualizer target state notification");
}
}
}
}
Oznámení Available se obdrží poté, co RemoteUserControl bylo vytvořeno a těsně před tím, než se zobrazí v nově vytvořeném okně nástroje vizualizéru. Pokud vizualizér zůstane otevřený, ostatní VisualizerTargetStateNotification hodnoty lze přijímat pokaždé, když cíl ladění změní svůj stav. Oznámení ValueUpdated se používá k označení, že poslední výraz otevřený vizualizérem byl úspěšně znovu vyhodnocen v místě, kde ladicí program zastavil, a měl by být aktualizován v uživatelském rozhraní. Na druhou stranu, kdykoli je cíl ladění obnoven nebo výraz nelze po zastavení znovu vyhodnotit, Unavailable oznámení bude přijato.
Aktualizace vizualizované hodnoty objektu
Pokud VisualizerTarget.IsTargetReplaceable je pravda, vizualizér ladicího programu může použít metodu ReplaceTargetObjectAsync k aktualizaci hodnoty vizualizovaného objektu v procesu ladění.
Zdroj objektu vizualizéru musí přepsat metodu CreateReplacementObject.
public override object CreateReplacementObject(object target, Stream incomingData)
{
// Use DeserializeFromJson to read from incomingData
// the new value of the object being visualized
...
return newValue;
}
Související obsah
Vyzkoušejte si ukázku RegexMatchDebugVisualizer a podívejte se na tyto techniky v akci.