Почему я не могу использовать лямбда-выражения при отладке в окне «Быстрый просмотр»?
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), все равно останется много сложностей, не в последнюю очередь из-за захваченных переменных, которые фундаментально реструктурируют код, который их использует (то, что вы думаете, как переменные, становится полями в классах, созданных компилятором) , немного дыма и зеркал.
Таким образом, я ни в малейшей степени не удивлен, что вы не можете использовать их праздно - есть много работы компилятора (и генерации типов за кулисами), которая поддерживает эту магию.
Нет, вы не можете использовать лямбда-выражения в окне просмотра / локальных / немедленных действий. Как заметил Марк, это невероятно сложно. Однако я хотел немного углубиться в эту тему.
Что большинство людей не учитывает при выполнении анонимной функции в отладчике, так это то, что это не происходит в вакууме. Сам процесс определения и запуска анонимной функции изменяет базовую структуру базы кода. Изменение кода в целом и, в частности, из непосредственного окна - очень сложная задача.
Рассмотрим следующий код.
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, она остановится на строке Break. А теперь представьте, если бы пользователь ввел в окно просмотра следующее:
(Func<int>)(() => v2);
Чтобы правильно выполнить это, отладчику (или, что более уместно, EE) потребуется создать закрытие для переменной v2. Это сложно, но возможно.
Что действительно затрудняет эту работу для EE, так это последняя строчка. Как теперь выполнить эту строку? По сути, анонимная функция удалила переменную v2 и заменила ее на closure2.v2. Итак, последняя строка кода действительно должна быть прочитана
var v3 = closure1.v1 + closure2.v2;
Тем не менее, чтобы получить этот эффект в коде, требуется, чтобы EE изменил последнюю строку кода, которая на самом деле является действием ENC. Хотя этот конкретный пример возможен, большая часть сценариев - нет.
Что еще хуже, выполнение этого лямбда-выражения не должно создавать нового замыкания. На самом деле он должен добавлять данные к исходному закрытию. На этом этапе вы сразу сталкиваетесь с ограничениями ENC.
К сожалению, мой небольшой пример лишь поверхностно затрагивает проблемы, с которыми мы сталкиваемся. Я все время говорю, что напишу полный пост в блоге на эту тему и, надеюсь, у меня будет время в эти выходные.
Вы не можете использовать лямбда-выражения в окнах Immediate или Watch.
Однако вы можете использовать выражения System.Linq.Dynamic , которые имеют форму .Where ("Id = @ 0", 2) - у него нет полного набора методов, доступных в стандартном Linq, и нет полного сила лямбда-выражений, но все же это лучше, чем ничего!
.Any(string predicate)
, вы можете поместить что-то вроде: .Where("Id>2").Any()
в окно просмотра или закрепить в исходном коде. Здорово!
Будущее наступило!
Поддержка отладки лямбда-выражений была добавлена в Visual Studio 2015 ( предварительная версия на момент написания).
Оценщик выражений пришлось переписать, поэтому многие функции отсутствуют: удаленная отладка ASP.NET, объявление переменных в окне Immediate, проверка динамических переменных и т. Д. Также в настоящее время не поддерживаются лямбда-выражения, требующие вызовов собственных функций.
это может помочь: Расширенное немедленное окно для Visual Studio (используйте Linq, Lambda Expr при отладке)
Всего наилучшего, Патрик
Лямбда-выражения не поддерживаются оценщиком выражений отладчика ... что неудивительно, поскольку во время компиляции они используются для создания методов (или деревьев выражений), а не выражений (посмотрите в Reflector с отображением, переключенным на .NET 2, чтобы увидеть их).
Плюс, конечно, они могут образовывать закрытие, еще один слой структуры.
Expression
деревья - это зависит от контекста.
В VS 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 \ ", столбец 'OranizationalRoleI \ nThe оператор был прерван. "} 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 }
Автор идеи можно найти здесь
Чтобы ответить на ваш вопрос, вот официальное объяснение Visual Studio Program Manager, почему вы не можете этого сделать. Короче говоря, потому что «это действительно очень сложно» реализовать в VS. Но эта функция в настоящее время находится в стадии разработки (по состоянию на август 2014 г.).
Разрешить оценку лямбда-выражений во время отладки
Добавьте свой голос, пока вы там!