Как получить поле DisplayString из Debugger.GetExpression?

Фон

Я пишу расширение Visual Studio на С#, которое выполняет код в окне Immediate при отладке другого приложения. Выражение возвращает значение, которое может быть целым числом, строковым литералом, классом и т. д. Приложение, которое я отлаживаю, написано на C++.

Код

Для выполнения команд Immediate Window я использую эту строку кода:

var expression = dte.Debugger.GetExpression("funcname()");

И для получения результата я использую:

string val = expression.Value;

а также:

var children = expression.DataMembers;

Вот myFunc() в приложении, которое я отлаживаю:

std::vector<int> myFunc()
{
    return { 1, 2, 3, 4, 5 };
}

Проблема

Когда я вручную запускаю выражение в окне Immediate Window, возвращаемый объект выгружается так, как я его вижу в окне Watch (см. здесь). Мне удалось найти имена всех дочерних элементов, но значения отсутствуют (см. здесь) .

Я хочу получить DisplayString ({ size=5 }), но пока не нашел ничего полезного.

Как получить поле DisplayString из Debugger.GetExpression?

EDIT: мне не нужно использовать этот API. Если вы знаете другой способ вернуть это жало, пожалуйста, предложите его. Одной из идей может быть получение полной выходной строки окна Immediate (см. справа ), а затем анализировать его.

EDIT2: посмотрите это видео, которое лучше объясняет проблему


person lax48    schedule 06.10.2020    source источник
comment
Привет, Лакс, если вы нажмете клавишу «раскрывающийся список» (разверните список) в окне просмотра рядом с string val= expression.Value;, как на снимке экрана, которым вы поделились, будет отображаться {size=5}?   -  person LoLance    schedule 07.10.2020
comment
@Lance К сожалению, expression.Value возвращает строку, поэтому то, что вы можете видеть на втором снимке экрана, - это то, что я получаю. Я пытался проверить переменную expression, но Value — единственное свойство, которое имеет смысл. Другими доступными свойствами являются Type, Name и DataMembers, но ни одно из них не содержит { size=5 }. Также есть свойство Collection, но оно всегда равно null, и я думаю, что это не решение моей проблемы. Что меня сводит с ума, так это то, что имена DataMembers следуют за визуализатором. Свойство value из них имеет ту же проблему.   -  person lax48    schedule 07.10.2020
comment
Привет, Лакс, я проверил этот документ: std:Vector и заметил, что size является функцией-членом std:Vector. И я думаю, что свойства выражения не могут получить size напрямую.   -  person Mr Qian    schedule 08.10.2020
comment
Привет Перри, спасибо за ваш комментарий. Я думаю, что недостаточно хорошо объяснил, в чем проблема: то, что я вижу в окне просмотра или в непосредственном окне, отличается от того, что мне удалось получить от GetExpression. { size=5 } — это отображаемая строка, определенная в файле визуализатора (.natvis). Если бы GetExpression не смог получить значение size, весь пользовательский визуализатор вышел бы из строя, и поэтому был бы использован тот, который используется по умолчанию. С другой стороны, если вы посмотрите на expression.DataMembers, вы увидите, что элементы соответствуют пользовательскому визуализатору.   -  person lax48    schedule 08.10.2020
comment
Извините, не обращайте внимания на ссылку на GitHub. Я невнимательно прочитал. Вот правильный пример: docs.microsoft.com/en-us/visualstudio/debugger/ (см. фрагмент кода XML в параграфе «Представления Natvis»)   -  person lax48    schedule 08.10.2020
comment
О, я только что понял, что вы сказали. Да, size() является функцией-членом класса std::vector, и, конечно же, свойства выражения не могут выполнять метод size(). Если вы посмотрите на пример natvis для std::vector в моем комментарии перед этим, вы увидите, что размер вычисляется путем вычитания конечного указателя из начального указателя (_Mylast - _Myfirst). Однако визуализатор корректно работает в Watch Window и Immediate Window, но не полностью работает с GetExpression() (дочерние элементы расширителя совпадают с именами в DataMembers, но значение параметра ...   -  person lax48    schedule 08.10.2020
comment
...выражение и у всех детей нет). Надеюсь, я был достаточно ясен.   -  person lax48    schedule 08.10.2020
comment
Спасибо за ваше подробное объяснение, я проверил еще раз, свойство Value действительно возвращает тип String, не уверен, что Sting можно изменить на int… И DataMembers возвращает коллекцию выражений, но она используется для получения коллекции выражений, вы можете проверьте этот пример и интерфейс выражений. Так что DataMembers может не работать.   -  person Mr Qian    schedule 09.10.2020
comment
@Perry спасибо за ответ, но я не могу понять, что вы имеете в виду, когда говорите, что «свойство Value действительно возвращает тип String, не уверен, что Sting можно изменить на int… И DataMembers действительно возвращают коллекцию выражений, но это используется для получения набора выражений». Я не хочу менять строку на int: я хочу, чтобы строка была "{ size=5 }" или как там написано в отображаемой строке в файле natvis.   -  person lax48    schedule 09.10.2020
comment
Также DataMembers содержит то, что я ожидаю. Я думаю, что я опубликую видео в своем вопросе, чтобы сделать его более понятным   -  person lax48    schedule 09.10.2020
comment
@PerryQian-MSFT Я только что загрузил видео, объясняющее проблему. См. EDIT2 в моем вопросе   -  person lax48    schedule 09.10.2020


Ответы (2)


вы использовали векторную переменную для получения/анализа возвращаемого значения функции, это разумно, потому что возвращаемый результат myFunc() является именно векторным типом, поэтому переменная «std::vector result» может правильно анализировать и получать векторный объект. Что вы имеете в виду под «ручным запуском выражения в окне Immediate Window, возвращаемый объект выгружается так, как я вижу его в окне Watch»?

В то время как EnvDTE.Expression.Value — это строка, представляющая значение объекта. Это не имеет ничего общего с отображаемой строкой ‘{ size=5 }’, это просто выражение свойства. Вы можете распечатать его с помощью приведенного ниже примера кода:

public static void Value(DTE dte)  
{  
    // Setup debug Output window.  
    Window w = (Window)dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);  
    w.Visible = true;  
    OutputWindow ow = (OutputWindow)w.Object;  
    OutputWindowPane owp = ow.OutputWindowPanes.Add("Value property: ");  
    owp.Activate();  

    EnvDTE.Expression exp = dte.Debugger.GetExpression("tempC", true, 1);  
    owp.OutputString("\nThe name of the expression: " + exp.Name);  
    owp.OutputString("\nThe type of the expression: " + exp.Type);  
    owp.OutputString("\nThe value of the expression: " + exp.Value);  
}

Таким образом, мы не можем получить '{size=5}' из окна немедленного просмотра здесь: введите здесь описание изображения

Относительно «строки отображения, определенной в файле визуализатора (.natvis)», свойство DisplayString должно быть изменено. Не могли бы вы предоставить файл визуализатора (.natvis) или пример проекта, который может воспроизвести проблему?

person Mia Wu-MSFT    schedule 27.01.2021
comment
Привет, большое спасибо за ответ. Пока я пытался создать демонстрационный проект, чтобы воспроизвести проблему, я наконец нашел, где проблема была в моем коде! Хитрость заключалась в том, чтобы поместить true в dte.Debugger.GetExpression("tempC", true)! Теперь expression.Value оценивается как "{ size=5 }", как и ожидалось! - person lax48; 02.03.2021
comment
Что касается вашего вопроса, я объясню, что я имел в виду для ручного запуска выражения в окне Immediate, возвращаемый объект сбрасывается, как я вижу его в окне Watch. Посмотрите на изображение в первом редактировании: я был в точке останова в моем целевом приложении, и я открыл окно просмотра слева и непосредственное окно справа. Как видите, информация, записанная в непосредственном окне, такая же, как и в окне просмотра, даже { size=5 } (это то, что я искал). Проблема была в том, что dte.Debugger.GetExpression("tempC").Value был "{..}" - person lax48; 02.03.2021
comment
Если вы отредактируете свой ответ, я приму его как окончательный ответ: просто скажите, что проблема заключалась в отсутствующем true и, если можете, скажите, что он делает (я не могу понять это из официальные документы). Еще раз спасибо! - person lax48; 02.03.2021

Я узнал, в чем проблема: я не передал UseAutoExpandRules (по умолчанию false) в GetExpression. Теперь мой код работает как положено!

Спасибо @Mia Wu-MSFT, которая добавила dte.Debugger.GetExpression("tempC", true, 1) в свой код и помогла мне найти аргумент UseAutoExpandRules.

person lax48    schedule 17.03.2021