Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Visualiserare för felsökningsprogram är en Visual Studio-funktion som tillhandahåller en anpassad visualisering för variabler eller objekt av en specifik .NET-typ under en felsökningssession.
Visualiserare för felsökningsprogram är tillgängliga från datatipset som visas när du hovrar över en variabel, eller från fönstren Autos, Locals och Watch :
              
              
            
Get started
Följ avsnittet Skapa tilläggsprojekt i avsnittet Komma igång.
Lägg sedan till en klass som ärver från DebuggerVisualizerProvider och tillämpa VisualStudioContribution-attributet på den.
/// <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);
    }
}
Den tidigare koden definierar en ny felsökningsvisualiserare, som gäller för objekt av typen string:
- Egenskapen 
DebuggerVisualizerProviderConfigurationdefinierar visningsnamnet för visualiseraren och den .NET-typ som stöds. - Metoden 
CreateVisualizerAsyncanropas av Visual Studio när användaren begär visning av felsökningsprogrammets visualiserare för ett visst värde.CreateVisualizerAsyncVisualizerTargetanvänder -objektet för att hämta värdet som ska visualiseras och skickar det till en anpassad fjärranvändarkontroll (referera till dokumentationen för fjärrgränssnittet). Fjärranvändarkontrollen returneras sedan och visas i ett popup-fönster i Visual Studio. 
Rikta in sig på flera typer
Med konfigurationsegenskapen kan visualiseraren rikta in sig på flera typer när det är praktiskt. Ett perfekt exempel på detta är DataSet Visualizer som stöder visualisering av DataSet, DataTable, DataViewoch DataViewManager objekt. Den här funktionen underlättar tilläggsutvecklingen eftersom liknande typer kan dela samma gränssnitt, vymodeller och visualiserarobjektkälla.
    /// <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)
    {
        ...
    }
Visualiserarobjektkällan
              Visualiserarens objektkälla är en .NET-klass som läses in av felsökaren i den process som felsöks. Visualiseraren för felsökningsprogrammet kan hämta data från visualiserarobjektkällan med hjälp av metoder som exponeras av VisualizerTarget.ObjectSource.
Standardobjektkällan för visualiseraren gör att felsökningsvisualiserare kan hämta värdet för objektet som ska visualiseras genom att anropa RequestDataAsync<T>(JsonSerializer?, CancellationToken) metoden. Standardobjektkällan för visualiseraren använder Newtonsoft.Json för att serialisera värdet, och VisualStudio.Extensibility-biblioteken använder även Newtonsoft.Json för deserialiseringen. Du kan också använda RequestDataAsync(CancellationToken) för att hämta det serialiserade värdet som en JToken.
Om du vill visualisera en .NET-typ som stöds internt av Newtonsoft.Json, eller om du vill visualisera din egen typ och du kan göra den serialiserbar, räcker de tidigare instruktionerna för att skapa en enkel felsökningsvisualiserare. Läs vidare om du vill stödja mer komplexa typer eller använda mer avancerade funktioner.
Använda en anpassad visualiserarobjektkälla
Om den typ som ska visualiseras inte automatiskt kan serialiseras av Newtonsoft.Json kan du skapa en anpassad visualiserarobjektkälla för att hantera serialiseringen.
- Skapa ett nytt .NET-klassbiblioteksprojekt för att rikta in sig på 
netstandard2.0. Du kan rikta in dig på en mer specifik version av .NET Framework eller .NET (till exempelnet472ellernet6.0) om det behövs för att serialisera objektet som ska visualiseras. - Lägg till en paketreferens till 
DebuggerVisualizersversion 17.6 eller senare. - Lägg till en klass som utökar 
VisualizerObjectSourceoch åsidosätterGetDataför att skriva det serialiserade värdet avtargettilloutgoingData-strömmen. 
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
        ...
    }
}
Använda anpassad serialisering
Du kan använda VisualizerObjectSource.SerializeAsJson metoden för att serialisera ett objekt med newtonsoft.Json till en Stream utan att lägga till en referens till Newtonsoft.Json i biblioteket. Vid anropa SerializeAsJson laddas, med reflektion, en version av sammansättningen Newtonsoft.Json in i processen som debuggas.
Om du behöver referera till Newtonsoft.Json bör du använda samma version som anges av Microsoft.VisualStudio.Extensibility.Sdk paketet, men det är bättre att använda DataContract och DataMember attribut för att stödja objektserialisering i stället för att förlita dig på Newtonsoft.Json-typer.
Du kan också implementera din egen anpassade serialisering (till exempel binär serialisering) som skriver direkt till outgoingData.
Lägg till visualiserarobjektets käll-DLL i tillägget
Ändra tilläggsfilen .csproj genom att lägga till en ProjectReference i visualiserarobjektets källbiblioteksprojekt, vilket ser till att visualiserarobjektets källbibliotek skapas innan tillägget paketeras.
Lägg också till ett Content objekt som innehåller visualiserarobjektets källbiblioteks-DLL i netstandard2.0 undermappen för tillägget.
  <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>
Du kan också använda undermapparna net4.6.2 eller netcoreapp om du har skapat visualiserarobjektets källbibliotek för .NET Framework eller .NET. Du kan även inkludera alla tre undermappar med olika versioner av visualiseringsobjektens källbibliotek, men det är bättre att endast fokusera på netstandard2.0.
Du bör försöka minimera antalet beroenden för visualiserarobjektets källbiblioteks-DLL. Om visualiserarobjektets källbibliotek har andra beroenden än Microsoft.VisualStudio.DebuggerVisualizers och bibliotek som redan garanterat kommer att läsas in under processen som debuggas ska du även inkludera DLL-filerna i samma undermapp som visualiserarobjektets källbiblioteks-DLL.
Uppdatera debuggerns visualiserarleverantör för att använda den anpassade visualiserarobjektkällan.
Du kan sedan uppdatera DebuggerVisualizerProvider konfigurationen för att referera till din anpassade visualiserarobjektkälla:
    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);
    }
Arbeta med stora och komplexa objekt
Om hämtningen av data från visualiserarobjektkällan inte kan göras med ett enda parameterlöst anrop till RequestDataAsynckan du i stället utföra ett mer komplext meddelandeutbyte med visualiserarobjektkällan genom att RequestDataAsync<TMessage, TResponse>(TMessage, JsonSerializer?, CancellationToken) anropa flera gånger och skicka olika meddelanden till visualiserarobjektkällan. Både meddelandet och svaret serialiseras av VisualStudio.Extensibility-infrastrukturen med newtonsoft.Json. Andra åsidosättningar av RequestDataAsync tillåter dig att använda JToken objekt eller implementera anpassad serialisering och deserialisering.
Du kan implementera alla anpassade protokoll med hjälp av olika meddelanden för att hämta information från visualiserarobjektkällan. Det vanligaste användningsfallet för den här funktionen är att bryta upp hämtningen av ett potentiellt stort objekt i flera anrop, för att undvika RequestDataAsync tidsgräns.
Det här är ett exempel på hur du kan hämta innehållet i en potentiellt stor samling ett objekt i taget:
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);
}
Koden ovan använder ett enkelt index som meddelande för anropen RequestDataAsync . Motsvarande visualiserarobjekts källkod skulle åsidosätta TransferData metoden (i stället GetDataför ):
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
        ...
    }
}
Visualiserarobjektkällan ovan använder VisualizerObjectSource.DeserializeFromJson metoden för att deserialisera meddelandet som skickas av visualiserarprovidern från incomingData.
När du implementerar en visualiserarprovider för felsökningsprogram som utför komplex meddelandeinteraktion med visualiserarobjektkällan är det vanligtvis bättre att skicka VisualizerTarget till visualiserarens RemoteUserControl så att meddelandeutbytet kan ske asynkront medan kontrollen läses in. Genom att skicka VisualizerTarget kan du också skicka meddelanden till visualiserarobjektkällan för att hämta data baserat på användarens interaktioner med visualiserarens användargränssnitt.
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
        ...
    }
    ...
Öppna visualiserare som verktygsfönster
Som standard öppnas alla visualiseringstillägg för felsökningsprogram som modala dialogrutor i förgrunden för Visual Studio. Om användaren vill fortsätta att interagera med IDE måste visualiseraren därför stängas. Men om egenskapen Style är inställd ToolWindow på i DebuggerVisualizerProviderConfiguration egenskapen öppnas visualiseraren som ett icke-modalt verktygsfönster som kan förbli öppet under resten av felsökningssessionen. Om inget format har deklarerats används standardvärdet 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);
    }
När en visualiserare väljer att öppnas som en ToolWindow, måste den prenumerera på StateChanged-eventet för VisualizerTarget. När en visualiserare öppnas som ett verktygsfönster blockeras inte användaren från att pausa felsökningssessionen. Den ovan nämnda händelsen utlöses därför av felsökaren när tillståndet för felsökningsmålet ändras. Visualiserartilläggsförfattare bör vara särskilt uppmärksamma på dessa meddelanden eftersom visualiserarmålet endast är tillgängligt när felsökningssessionen är aktiv och felsökningsmålet har pausats. När visualiserarmålet inte är tillgängligt, kommer anrop till ObjectSource-metoder att misslyckas med en 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");
            }
        }
    }
}
Meddelandet Available tas emot efter att det RemoteUserControl har skapats och precis innan det görs synligt i det nyligen skapade visualiserarverktygsfönstret. Så länge visualiseraren förblir öppen kan de andra VisualizerTargetStateNotification värdena tas emot varje gång felsökningsmålet ändrar sitt tillstånd. Meddelandet ValueUpdated används för att indikera att det senaste uttrycket som öppnades av visualiseraren utvärderades på nytt där felsökningsprogrammet stoppades och bör uppdateras av användargränssnittet. Å andra sidan tas meddelandet emot när felsökningsmålet återupptas eller om uttrycket inte kan utvärderas igen efter att det Unavailable har stoppats.
Uppdatera det visualiserade objektvärdet
Om VisualizerTarget.IsTargetReplaceable är sant kan felsökningsvisualiseraren ReplaceTargetObjectAsync använda metoden för att uppdatera värdet för det visualiserade objektet i processen som debuggas.
Visualiserarobjektkällan måste åsidosätta CreateReplacementObject metoden:
public override object CreateReplacementObject(object target, Stream incomingData)
{
    // Use DeserializeFromJson to read from incomingData
    // the new value of the object being visualized
    ...
    return newValue;
}
Relaterat innehåll
Prova exemplet RegexMatchDebugVisualizer om du vill se de här teknikerna i praktiken.