Отладка Visual Studio, инструмент "быстрого наблюдения" и лямбда-выражения - PullRequest
94 голосов
/ 07 апреля 2009

Почему я не могу использовать лямбда-выражения при отладке в окне «Quick watch»?

UPD: см. Также

http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx

http://blogs.msdn.com/b/jaredpar/archive/2010/06/02/why-is-linq-absent-from-debugger-windows-part-2.aspx

Ответы [ 9 ]

91 голосов
/ 07 апреля 2009

Нет, вы не можете использовать лямбда-выражения в окне просмотра / локальных / непосредственных сообщений. Как отметил Марк, это невероятно сложно. Я хотел погрузиться немного дальше в тему, хотя.

То, что большинство людей не учитывают при выполнении анонимной функции в отладчике, это то, что она не возникает в вакууме. Сам процесс определения и запуска анонимной функции меняет основную структуру базы кода. Изменение кода, в целом и, в частности, из непосредственного окна, является очень сложной задачей.

Рассмотрим следующий код.

void Example() {
  var v1 = 42;
  var v2 = 56; 
  Func<int> func1 = () => v1;
  System.Diagnostics.Debugger.Break();
  var v3 = v1 + v2;
}

Этот конкретный код создает одно замыкание для захвата значения v1. Захват закрытия требуется всякий раз, когда анонимная функция использует переменную, объявленную вне ее области видимости. Для всех намерений и целей v1 больше не существует в этой функции. Последняя строка на самом деле больше похожа на следующую

var v3 = closure1.v1 + v2;

Если в примере отладчика запущена функция Example, она остановится на линии разрыва. Теперь представьте, что пользователь набрал следующее в окне просмотра

(Func<int>)(() => v2);

Чтобы правильно выполнить это, отладчику (или, более подходящему, EE) потребуется создать замыкание для переменной v2. Это сложно, но не невозможно сделать.

Что действительно делает эту тяжелую работу для EE, так это последняя строка. Как теперь должна выполняться эта строка? Для всех целей анонимная функция удалила переменную v2 и заменила ее на closure2.v2. Таким образом, последняя строка кода действительно должна читаться как

var v3 = closure1.v1 + closure2.v2;

Тем не менее, чтобы фактически получить этот эффект в коде, требуется, чтобы EE изменило последнюю строку кода, которая фактически является действием ENC. Хотя этот конкретный пример возможен, большая часть сценариев не возможна.

Что еще хуже, выполнение лямбда-выражения не должно создавать новое замыкание. На самом деле это должно быть добавление данных к исходному закрытию. В этот момент вы попадаете прямо в ограничения ENC.

Мой маленький пример, к сожалению, только царапает поверхность проблем, с которыми мы сталкиваемся. Я продолжаю говорить, что напишу полный пост в блоге на эту тему и, надеюсь, у меня будет время на этих выходных.

63 голосов
/ 07 апреля 2009

Лямбда-выражения, как и анонимные методы, на самом деле очень сложные звери. Даже если мы исключим Expression (.NET 3.5), это по-прежнему оставляет лот сложности, не в последнюю очередь перехваченные переменные, которые принципиально реструктурируют код, который их использует (то, что вы думаете как переменные становятся полями в сгенерированных компилятором классах), с небольшим количеством дыма и зеркал.

Таким образом, я нисколько не удивлен, что вы не можете использовать их без дела - есть серия работы компилятора (и генерация типов за кулисами), которая поддерживает эту магию.

49 голосов
/ 05 мая 2010

Вы не можете использовать лямбда-выражения в окнах Immediate или Watch.

Однако вы можете использовать System.Linq.Dynamic выражений , которые принимают форму .Where ("Id = @ 0", 2) - он не имеет полного набора методов, доступных в стандарте Linq, и не обладает всей мощью лямбда-выражений, но все же лучше, чем ничего!

21 голосов
/ 13 ноября 2014

будущее наступило!

Добавлена ​​поддержка отладки лямбда-выражений в Visual Studio 2015 ( Предварительный просмотр на момент написания).

Expression Evaluator пришлось переписать, поэтому многие функции отсутствуют: удаленная отладка ASP.NET, объявление переменных в окне Immediate, проверка динамических переменных и т. Д. Также в настоящее время не поддерживаются лямбда-выражения, требующие вызовов собственных функций.

5 голосов
/ 16 апреля 2009

это может помочь: Расширенное немедленное окно для Visual Studio (используйте Linq, Lambda Expr для отладки)

Всего наилучшего, Patrick

2 голосов
/ 07 апреля 2009

Лямбда-выражения не поддерживаются оценщиком выражений отладчика ... что неудивительно, поскольку во время компиляции они используются для создания методов (или деревьев выражений), а не выражений (взгляните на Reflector с переключенным отображением на. NET 2, чтобы увидеть их).

Плюс, конечно, они могут образовать замыкание, еще один целый слой структуры.

1 голос
/ 05 декабря 2015

В VS 2015 вы можете сделать это сейчас, это одна из новых функций, которые они добавили.

1 голос
/ 15 сентября 2015

Если вам все еще нужно использовать Visual Studio 2013, вы можете написать цикл или лямбда-выражение в непосредственном окне, используя также окно консоли диспетчера пакетов. В моем случае я добавил список вверху функции:

private void RemoveRoleHierarchy()
{
    #if DEBUG
    var departments = _unitOfWork.DepartmentRepository.GetAll().ToList();
    var roleHierarchies = _unitOfWork.RoleHierarchyRepository.GetAll().ToList();
    #endif

    try
    {
        //RoleHierarchy
        foreach (SchoolBo.RoleHierarchy item in _listSoRoleHierarchy.Where(r => r.BusinessKeyMatched == false))
            _unitOfWork.RoleHierarchyRepository.Remove(item.Id);

        _unitOfWork.Save();
    }
    catch (Exception e)
    {
        Debug.WriteLine(e.ToString());
        throw;
    }
}

Где моя GetAll() функция:

private DbSet<T> _dbSet;

public virtual IList<T> GetAll()
{
    List<T> list;
    IQueryable<T> dbQuery = _dbSet;
    list = dbQuery
        .ToList<T>();

    return list;
}

Здесь я продолжал получать следующую ошибку, поэтому я хотел распечатать все элементы в различных репозиториях:

InnerException {"Оператор DELETE конфликтовал с ограничением REFERENCE \" FK_dbo.Department_dbo.RoleHierarchy_OranizationalRoleId \ ". Конфликт произошел в базе данных \" CC_Portal_SchoolObjectModel \ ", таблице \" dbo.Department \ ", столбце" Oraniz. r \ nОпределение завершено. "} System.Exception {System.Data.SqlClient.SqlException}

Затем я выясняю, сколько записей в хранилище отдела, выполнив это в ближайшем окне:

_unitOfWork.DepartmentRepository.GetAll().ToList().Count

Который вернул 243.

Итак, если вы выполните следующее в консоли диспетчера пакетов, он распечатает все элементы:

PM> for($i = 0; $i -lt 243; $i++) { $a = $dte.Debugger.GetExpression("departments[$i].OrgagnizationalRoleId"); Write-Host $a.Value $i }

Автор идеи можно найти здесь

1 голос
/ 17 сентября 2014

Чтобы ответить на ваш вопрос, вот официальное объяснение менеджера программ Visual Studio, почему вы не можете этого сделать. Короче говоря, потому что «это действительно очень трудно» реализовать в VS. Но функция в настоящее время в процессе (как обновлено в августе 2014 года).

Разрешить оценку лямбда-выражений при отладке

Добавь свой голос, пока ты там!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...