Почему я не могу использовать лямбда-выражения во время отладки в окне быстрого просмотра?
UPD: см. также
http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx
Почему я не могу использовать лямбда-выражения во время отладки в окне быстрого просмотра?
UPD: см. также
http://blogs.msdn.com/b/jaredpar/archive/2009/08/26/why-no-linq-in-debugger-windows.aspx
Лямбда-выражения, как и анонимные методы, на самом деле являются очень сложными животными. Даже если мы исключаем Expression
(.NET 3.5), который по-прежнему оставляет много сложностей, не в последнюю очередь являясь захваченными переменными, которые в корне переструктурируют код, который их использует (то, что вы считаете переменными, становятся полями в компиляторе, генерируемые классы), с небольшим количеством дыма и зеркал.
Как таковой, я ничуть не удивлен, что вы не можете использовать их idly - есть много работы с компилятором (и генерация типа за кулисами), которая поддерживает эту магию.
Нет, вы не можете использовать лямбда-выражения в часах/локалях/немедленном окне. Марк отметил, что это невероятно сложно. Однако я хотел еще немного погрузиться в эту тему.
То, что большинство людей не учитывает при выполнении анонимной функции в отладчике, заключается в том, что оно не происходит в вакууме. Сам акт определения и запуска анонимной функции изменяет базовую структуру базы кода. Изменение кода, в общем, и, в частности, из непосредственного окна, является очень сложной задачей.
Рассмотрим следующий код.
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 и заменила ее на clos2.v2. Таким образом, последняя строка кода действительно нуждается в чтении
var v3 = closure1.v1 + closure2.v2;
Однако для фактического получения этого эффекта в коде требуется, чтобы EE изменила последнюю строку кода, которая фактически является действием ENC. Хотя этот конкретный пример возможен, хорошей частью сценариев нет.
Что еще хуже, выполнение этого лямбда-выражения не должно создавать новое замыкание. Фактически это должно быть добавление данных к первоначальному закрытию. На этом этапе вы бежите прямо в ограничения ENC.
Мой маленький пример, к сожалению, только царапает поверхность проблем, с которыми мы сталкиваемся. Я продолжаю говорить, что напишу полный блог на эту тему, и, надеюсь, у меня будет время в эти выходные.
Вы не можете использовать лямбда-выражения в окнах Immediate или Watch.
Однако вы можете использовать System.Linq.Dynamic выражения, которые принимают форму .Where( "Id = @0", 2) - он не обладает полным набором методов, доступных в стандартном Linq, и не имеет полной мощности лямбда-выражений, но все же это лучше, чем ничего!
Будущее пришло!
Поддержка отладки лямбда-выражений добавлена в Visual Studio 2015 (предварительный просмотр на момент написания).
Оценщик выражений должен был быть перезаписан, поэтому не хватает многих функций: удаленная отладка ASP.NET, объявление переменных в окне Immediate, проверка динамических переменных и т.д. Также в настоящее время не поддерживаются лямбда-выражения, которые требуют вызова собственных функций.
это может помочь: Extended Immediate Window для Visual Studio (используйте Linq, Lambda Expr для отладки)
Все самое лучшее, Патрик
Лямбда-выражения не поддерживаются оценщиком выражений отладчика... что неудивительно, поскольку во время компиляции они используются для создания методов (или деревьев выражений), а не для выражений (взгляните на Reflector с включенным дисплеем).NET 2, чтобы увидеть их).
Плюс, конечно, они могли бы образовать замыкание, еще один целый слой структуры.
Чтобы ответить на ваш вопрос, здесь официальное объяснение менеджера программ Visual Studio о том, почему вы не можете этого сделать. Короче говоря, потому что "это действительно, действительно сложно" реализовать в VS. Но эта функция в настоящее время выполняется (обновлено в августе 2014 года).
Разрешить оценку лямбда-выражений во время отладки
Добавьте свой голос, пока вы там!
Если вам все еще нужно использовать 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 ", столбец" OranizationalRoleId ".\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 }
Автор идеи можно найти здесь
В VS 2015 вы можете сделать это сейчас, это одна из новых функций, которые они добавили.