Visual Studio hata ayıklayıcısı görselleştiricileri oluşturma

Hata ayıklayıcı görselleştiricileri, hata ayıklama oturumu sırasında belirli bir .NET türüne ait değişkenler veya nesneler için özel görselleştirme sağlayan bir Visual Studio özelliğidir.

Hata ayıklayıcısı görselleştiricilerine bir değişkenin üzerine gelindiğinde görüntülenen Veri İpucu'ndan veya OtomatikLer, Yerel öğeler ve İzleme pencerelerinden erişilebilir:

Screenshot of debugger visualizers in the watch window.

Kullanmaya başlayın

Başlarken bölümündeki Uzantı projesini oluşturma bölümünü izleyin.

Ardından, genişleten DebuggerVisualizerProvider bir sınıf ekleyin ve özniteliğini VisualStudioContribution uygulayın:

/// <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);
    }
}

Önceki kod, türündeki stringnesnelere uygulanan yeni bir hata ayıklayıcısı görselleştiricisi tanımlar:

  • özelliği görselleştirici DebuggerVisualizerProviderConfiguration görünen adını ve desteklenen .NET türünü tanımlar.
  • Kullanıcı CreateVisualizerAsync belirli bir değer için hata ayıklayıcı görselleştiricisinin görüntülenmesini istediğinde yöntemi Visual Studio tarafından çağrılır. CreateVisualizerAsyncVisualizerTarget görselleştirilecek değeri almak için nesnesini kullanır ve özel bir uzak kullanıcı denetimine geçirir (Uzak kullanıcı arabirimi belgelerine başvurun). Daha sonra uzak kullanıcı denetimi döndürülür ve Visual Studio'daki bir açılır pencerede gösterilir.

Birden çok türü hedefleme

yapılandırma özelliği, görselleştiricinin uygun olduğunda birden çok türü hedeflemesine olanak tanır. Bunun mükemmel bir örneği, , , DataTableve nesnelerinin görselleştirmesini destekleyen DataSet Görselleştiricisi'dir DataSet.DataViewManagerDataView Benzer türler aynı kullanıcı arabirimini, görüntüleme modellerini ve görselleştirici nesne kaynağını paylaşabildiğinden bu özellik uzantı geliştirmeyi kolaylaştırır.

    /// <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)
    {
        ...
    }

Görselleştirici nesne kaynağı

Görselleştirici nesne kaynağı , hata ayıklanırken hata ayıklayıcı tarafından yüklenen bir .NET sınıfıdır. Hata ayıklayıcı görselleştiricisi tarafından VisualizerTarget.ObjectSourcekullanıma sunulan yöntemleri kullanarak görselleştirici nesne kaynağından veri alabilir.

Varsayılan görselleştirici nesne kaynağı, hata ayıklayıcı görselleştiricilerinin yöntemini çağırarak RequestDataAsync<T>(JsonSerializer?, CancellationToken) görselleştirilecek nesnenin değerini almasını sağlar. Varsayılan görselleştirici nesne kaynağı değeri seri hale getirmek için Newtonsoft.Json,VisualStudio.Genişletilebilirlik kitaplıkları da seri durumdan çıkarma için Newtonsoft.Json kullanır. Alternatif olarak, serileştirilmiş değeri olarak JTokenalmak için kullanabilirsinizRequestDataAsync(CancellationToken).

Newtonsoft.Json tarafından yerel olarak desteklenen bir .NET türünü görselleştirmek veya kendi türünüzü görselleştirmek ve serileştirilebilir hale getirmek istiyorsanız, önceki yönergeler basit bir hata ayıklayıcı görselleştiricisi oluşturmak için yeterlidir. Daha karmaşık türleri desteklemek veya daha gelişmiş özellikler kullanmak istiyorsanız okumaya devam edin.

Özel görselleştirici nesne kaynağı kullanma

Görselleştirilecek tür Newtonsoft.Json tarafından otomatik olarak serileştirilemiyorsa, serileştirmeyi işlemek için özel bir görselleştirici nesne kaynağı oluşturabilirsiniz.

  • hedefleyen yeni bir .NET sınıf kitaplığı projesi netstandard2.0oluşturun. Görselleştirilecek nesneyi seri hale getirmek için gerekirse daha belirli bir .NET Framework veya .NET sürümünü (örneğin, net472 veya net6.0) hedefleyebilirsiniz.
  • Sürüm 17.6 veya daha yeni bir sürüme DebuggerVisualizers paket başvurusu ekleyin.
  • Akışına serileştirilmiş değerini targetoutgoingData yazarak genişleten VisualizerObjectSource ve geçersiz kılan GetData bir sınıf ekleyin.
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
        ...
    }
}

Özel serileştirme kullanma

Newtonsoft.Json kullanarak kitaplığınıza Newtonsoft.Json başvurusu eklemeden bir Stream nesnesine seri hale getirmek için yöntemini kullanabilirsinizVisualizerObjectSource.SerializeAsJson. Çağırma SerializeAsJson , hata ayıklanan işleme Newtonsoft.Json derlemesinin bir sürümünü yansıtma yoluyla yükler.

Newtonsoft.Json'a başvurmanız gerekiyorsa, paket tarafından Microsoft.VisualStudio.Extensibility.Sdk başvuruda bulunan sürümü kullanmanız gerekir, ancak Newtonsoft.Json türlerine güvenmek yerine nesne serileştirmeyi desteklemek için ve DataMember özniteliklerini kullanmanız DataContract tercih edilir.

Alternatif olarak, doğrudan öğesine outgoingDatayazarak kendi özel serileştirmenizi (ikili serileştirme gibi) uygulayabilirsiniz.

Uzantıya görselleştirici nesne kaynağı DLL'sini ekleme

Görselleştirici nesne kaynak kitaplığı projesine bir ProjectReference ekleyen uzantı .csproj dosyasını değiştirin. Bu, görselleştirici nesne kaynak kitaplığının uzantı paketlenmesinin öncesinde derlendiğinden emin olur.

Ayrıca uzantının alt klasörüne görselleştirici nesne kaynak kitaplığı DLL'sini netstandard2.0 içeren bir Content öğe ekleyin.

  <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>

Alternatif olarak, .NET Framework veya .NET'i hedefleyen görselleştirici nesne kaynak kitaplığını derlediyseniz veya netcoreapp alt klasörlerini kullanabilirsiniznet4.6.2. Görselleştirici nesne kaynak kitaplığının farklı sürümlerine sahip üç alt klasörü de ekleyebilirsiniz, ancak yalnızca hedeflemek netstandard2.0 daha iyidir.

Görselleştirici nesne kaynak kitaplığı DLL'sinin bağımlılık sayısını en aza indirmeyi denemelisiniz. Görselleştirici nesne kaynak kitaplığınızda microsoft.VisualStudio.DebuggerVisualizers dışında bağımlılıklar varsa ve zaten hata ayıklanan işlemde yüklenmesi garanti edilen kitaplıklar varsa, bu DLL dosyalarını görselleştirici nesne kaynak kitaplığı DLL'si ile aynı alt klasöre de eklediğinizden emin olun.

Özel görselleştirici nesne kaynağını kullanmak için hata ayıklayıcı görselleştirici sağlayıcısını güncelleştirin

Ardından özel görselleştirici nesne kaynağınıza başvurmak için yapılandırmanızı DebuggerVisualizerProvider güncelleştirebilirsiniz:

    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);
    }

Büyük ve karmaşık nesnelerle çalışma

Görselleştirici nesne kaynağından veri alma işlemi tek bir parametresiz çağrısıyla RequestDataAsyncyapılamıyorsa, bunun yerine birden çok kez çağırıp RequestDataAsync<TMessage, TResponse>(TMessage, JsonSerializer?, CancellationToken) görselleştirici nesne kaynağına farklı iletiler göndererek görselleştirici nesne kaynağıyla daha karmaşık bir ileti değişimi gerçekleştirebilirsiniz. hem ileti hem de yanıt, Newtonsoft.Json kullanılarak VisualStudio.Genişletilebilirlik altyapısı tarafından serileştirilir. diğer geçersiz kılmaları RequestDataAsync nesneleri kullanmanıza JToken veya özel serileştirme ve seri durumdan çıkarma gerçekleştirmenize olanak sağlar.

Görselleştirici nesne kaynağından bilgi almak için farklı iletiler kullanarak herhangi bir özel protokolü uygulayabilirsiniz. Bu özelliğin en yaygın kullanım örneği, zaman aşımını önlemek RequestDataAsync için büyük olabilecek bir nesnenin alınmasını birden çok çağrıya bölmektir.

Bu, büyük olabilecek bir koleksiyonun içeriğini bir kerede bir öğeyi nasıl alabileceğinize ilişkin bir örnektir:

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);
}

Yukarıdaki kod, çağrılar için RequestDataAsync ileti olarak basit bir dizin kullanır. Karşılık gelen görselleştirici nesne kaynak kodu yöntemini geçersiz kılar TransferData (yerine 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
        ...
    }
}

Yukarıdaki görselleştirici nesne kaynağı, görselleştirici sağlayıcısı tarafından 'den gönderilen iletiyi seri durumdan çıkarmak için yönteminden incomingDatayararlanırVisualizerObjectSource.DeserializeFromJson.

Görselleştirici nesne kaynağıyla karmaşık ileti etkileşimi gerçekleştiren bir hata ayıklayıcı görselleştirici sağlayıcısı uygularken, denetim yüklenirken ileti değişiminin zaman uyumsuz olarak gerçekleşmesi için öğesini görselleştiriciye RemoteUserControl geçirmek VisualizerTarget genellikle daha iyidir. geçişi VisualizerTarget , kullanıcının görselleştiricinin kullanıcı arabirimiyle etkileşimlerine göre verileri almak için görselleştirici nesne kaynağına ileti göndermenize de olanak tanır.

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
        ...
    }
    ...

Görselleştiricileri Araç Pencereleri olarak açma

Varsayılan olarak, tüm hata ayıklayıcı görselleştirici uzantıları Visual Studio'nun ön planında kalıcı iletişim penceresi olarak açılır. Bu nedenle, kullanıcı IDE ile etkileşime devam etmek istiyorsa görselleştiricinin kapatılması gerekir. Ancak özelliği özelliğinde DebuggerVisualizerProviderConfiguration olarak ayarlanırsa StyleToolWindow görselleştirici, hata ayıklama oturumunun geri kalanında açık kalabilen kalıcı olmayan bir araç penceresi olarak açılır. Hiçbir stil bildirilmemişse, varsayılan değer ModalDialog kullanılır.

    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);
    }

Bir görselleştirici olarak açılmayı ToolWindowtercih ettiyse, öğesinin StateChanged olayına VisualizerTargetabone olması gerekir. Görselleştirici araç penceresi olarak açıldığında, kullanıcının hata ayıklama oturumunu açmasını engellemez. Bu nedenle, hata ayıklama hedefinin durumu her değiştiğinde, yukarıda belirtilen olay hata ayıklayıcı tarafından tetiklenir. Görselleştirici hedefi yalnızca hata ayıklama oturumu etkin olduğunda ve hata ayıklama hedefi duraklatıldığında kullanılabildiğinden, görselleştirici uzantısı yazarlarının bu bildirimlere özellikle dikkat etmesi gerekir. Görselleştirici hedefi kullanılabilir olmadığında, yöntemlere ObjectSource yapılan çağrılar ile VisualizerTargetUnavailableExceptionbaşarısız olur.

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");
            }
        }
    }
}

Bildirim Available oluşturulduktan sonra RemoteUserControl ve yeni oluşturulan görselleştirici araç penceresinde görünür hale getirilmeden hemen önce alınır. Görselleştirici açık kaldığı sürece, hata ayıklama hedefi durumunu her değiştirişinde diğer VisualizerTargetStateNotification değerler alınabilir. Bildirim ValueUpdated , görselleştirici tarafından açılan son ifadenin hata ayıklayıcının durduğu yerde başarıyla yeniden değerlendirildiğini ve kullanıcı arabirimi tarafından yenilenmesi gerektiğini belirtmek için kullanılır. Öte yandan, hata ayıklama hedefi devam ettirildiğinde veya durdurulduğu zaman ifade yeniden değerlendirilemediğinde Unavailable bildirim alınır.

Görselleştirilmiş nesne değerini güncelleştirme

VisualizerTarget.IsTargetReplaceable True ise, hata ayıklayıcı görselleştiricisi hata ayıklanan işlemde görselleştirilmiş nesnenin değerini güncelleştirmek için yöntemini kullanabilirReplaceTargetObjectAsync.

Görselleştirici nesne kaynağı yöntemini geçersiz kılmalıdır 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;
}

RegexMatchDebugVisualizer Bu teknikleri çalışırken görmek için örneği deneyin.