Отладка при помощи средств визуализации отладчика (Debugger Visualizers) Visual Studio 2005 - Создаем специализированное cредство визуализации

ОГЛАВЛЕНИЕ

Создаем специализированное cредство визуализации

Создание специализированного cредства визуализации обычно подразумевает создание трех связанных объектов:

  1. класс cредства визуализации ("visualizer") - когда разработчик нажимает на иконку увеличительного стекла во время сессии отладки, мы должны каким-то образом связать соответствующий объект и отобразить информацию в желаемом формате. Действие получения информации объекта из отладчика и передачи ее в пользовательский интерфейс является ответственностью класса cредства визуализации. Данный класс наследуется от класса DialogDebuggerVisualizer и предоставляет метод Show() , который отвечает за получение информации и вызов пользовательского интерфейса. Данный класс также должен содержать атрибут сборки, обозначающий, что cредство визуализации является подходящего типа данных .
  2. класс источника ("source") - ответственностью класса источника является взятие объекта, чья иконка увеличительного стекла была нажата, и передача данной информации объекта в отладчик. Данный класс наследуется от VisualizerObjectSource и обладает методом GetData(object, Stream), который предоставляет  сериализированную версию объекта классу cредства визуализации. В частности, первым входным параметром метода GetData() является объект, чья иконка увеличительного стекла была нажата; вторым входным параметром является Stream (поток), к которому объект должен быть сериализирован.
  3. пользовательский интерфейс ("user interface") - пользовательский интерфейс, который отобразит информацию. Обычно это подразумевает создание формы (либо нескольких), добавление соответствующих элементов пользовательского интерфейса (TextBoxe, TreeView, и т.д.), а также передачу классом cредства визуализации информации для отображения.
Для того чтобы продемонстрировать данное взаимодействие, я создал достаточно простое cредство визуализации, разработанное для отображения серверных переменных. Данное cредство визуализации ассоциировано с классом System.Web.UI.Page class. (Вы можете загрузить данный класс в конце статьи.)

Давайте рассмотрим исходный класс. Метод GetData() здесь начинается с преобразования первого входного параметра в объект Page и затем сброса значений коллекции Request.ServerVariables в новую NameValueCollection. (Я произвожу данное детальное копирование, поскольку Request.NameValueCollection на самом деле является объектом типа HttpServerVarsCollection, который не является сериализированным, следовательно,  не может быть переслан из исходного класса в класс cредства визуализации. Коллекция NameValueCollection является сериализируемой, тем не менее после сброса содержимого из Request.NameValueCollection в локальную NameValueCollection я затем сериализирую содержимое в поток (Stream), который был передан в качестве второго входного параметра):

public override void GetData(object target, System.IO.Stream outgoingData)
{
    if (target != null && target is Page)
    {
        Page p = (Page)target;

        // Помещаем содержимое из Request.ServerVariables в
        // локальное NameValueCollection b/c Request.ServerVariables
        // не является сериализированным...
        NameValueCollection nvc = new NameValueCollection();
        foreach (string key in p.Request.ServerVariables)
            nvc.Add(key, p.Request.ServerVariables[key]);

        // сериализация nvc в поток outgoingData
        BinaryFormatter formatter = new BinaryFormatter();
        formatter.Serialize(outgoingData, nvc);
    }
}

Далее, в методе Show() класса cредства визуализации мы десериализируем информацию из метода GetData() и создаем пользовательский интерфейс. Это выполняется при помощи данного кода:

protected override void Show(IDialogVisualizerService windowService,
                             IVisualizerObjectProvider objectProvider)
{
    // Десериализация Stream возвращенного GetData() в NameValueCollection
    NameValueCollection vars = null;
    using (Stream dataStream = objectProvider.GetData())
    {
        BinaryFormatter formatter = new BinaryFormatter();
        vars = formatter.Deserialize(dataStream) as NameValueCollection;
    }

    // Создаем форму пользовательского интерфейса,передавая в NameValueCollection
    using (VisualizerForm displayForm = new VisualizerForm())
    {
        displayForm.Visualize(vars);
        windowService.ShowDialog(displayForm);
    }
}

Класс VisualizerForm является Windows Form, содержащей элемент управления ListView. Метод Visualize(NameValueCollection) класса VisualizerForm (написанный мною), берет переданный объект NameValueCollection и сбрасывает его содержимое в ListView.

Также в класс cредства визуализации включен атрибут DebuggerVisualizer, который связывает средство с типом данных System.Web.UI.Page:

[assembly: DebuggerVisualizer(
    typeof(skmVisualizers.ServerVariables.Visualizer),
    typeof(skmVisualizers.ServerVariables.ServerVariablesControlSource),
    Target = typeof(System.Web.UI.Page),
    Description = "Visualize the page's server variables.")]