Інструмент налагодження «швидкого годинника» та лямбда-вирази у Visual Studio


96

Чому я не можу використовувати лямбда-вирази під час налагодження у вікні “Швидкий перегляд”?

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


5
Це було завершено та доступно у попередньому перегляді VS 2015. visualstudio.uservoice.com/forums/121579-visual-studio/…
Франсіско д'Анконія


я спробував дуже простий приклад, наведений на MSDN для лямбда-виразу, але він не працює. у мене випуск VS 2015 для підприємств
Адем

2
@ Franciscod'Anconia, щоб увімкнути підтримку лямбда-сигналу під час налагодження, потрібно встановити прапорець "Використовувати режим керованої сумісності" ( stackoverflow.com/a/36559817/818321 ) Як результат, ви не зможете використовувати умовні точки зупинку : blogs.msdn .microsoft.com / devops / 2013/10/16 /… та stackoverflow.com/a/35983978/818321
Нік

Відповіді:


64

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

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


91

Ні, ви не можете використовувати лямбда-вирази у годиннику / місцевих жителях / безпосередньому вікні. Як зазначав Марк, це надзвичайно складно. Хоча я хотів заглибитися трохи далі в тему.

Більшість людей не враховують, виконуючи анонімну функцію в налагоджувачі, це те, що вона не відбувається у вакуумі. Сам акт визначення та запуску анонімної функції змінює базову структуру основи коду. Зміна коду, загалом, і зокрема з безпосереднього вікна, є дуже складним завданням.

Розглянемо наступний код.

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. Це важко, але не неможливо зробити.

Однак насправді це важка робота для ЕЕ - це останній рядок. Як тепер слід виконувати цей рядок? Для всіх намірів і цілей анонімна функція видалила змінну v2 і замінила її на closure2.v2. Тож останній рядок коду справді тепер потрібно прочитати

var v3 = closure1.v1 + closure2.v2;

Однак для того, щоб насправді отримати цей ефект у коді, потрібно, щоб EE змінив останній рядок коду, який насправді є дією ENC. Хоча цей конкретний приклад можливий, значна частина сценаріїв - ні.

Що ще гірше, виконуючи, що лямбда-вираз не повинен створювати нове закриття. Насправді це має бути додавання даних до початкового закриття. На цьому етапі ви впадаєте прямо в обмеження ENC.

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


41
Нити, скиглити, прийми посередність, скиглити, скиглити. Налагоджувач - це серце IDE, і ви його зламали! Лямбди у годинниковому вікні не потрібно нічого фіксувати. Як і будь-який інший код годинника, вони мають сенс лише в певному кадрі стека. (Або ви захопите змінну, перейдете до іншої функції з тим самим іменем змінної ... і що?) Налагоджувач призначений для злому компілятора. Нехай це працює!
Олександр Дубінський

2
Чому вони просто не дозволяють фіксувати змінні на лямбдах у вікні годинника. Простий і дозволить купу сценаріїв налагодження, коли лямбди просто використовуються у справді функціональному коді.
Луїс Феліпе,

@LuizFelipe навіть це все ще є масовим захопленням. Це вимагає, щоб EE насправді генерував повноцінне тіло функції для зворотного дзвінка (аж до IL). Сьогодні EE нічого подібного не робить, натомість це інтерпретатор.
JaredPar

1
@JaredPar, чи можете ви поділитися публікацією в блозі, про яку Марк говорить
Ехсан Саджад,

49

Ви не можете використовувати лямбда-вирази у вікнах Безпосереднього або Дивитися.

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


2
Ну ... тоді як інші пояснювали, поки це було неможливо, це принаймні надає нам можливе рішення. +1
Нуллій

1
Тільки для уточнення, ви "Імпортуєте System.Linq.Dynamic", а потім у вікні налагодження пишете '"Де (щось. AsQueryable," властивість> xyz ", нічого)'
smirkingman

Це чудово. Незважаючи на те, що ви не отримуєте повного набору методів розширення Linq, наприклад, їх немає .Any(string predicate), ви можете помістити щось на зразок: .Where("Id>2").Any()у Вікно спостереження або Закріпити до джерела. Це чудово!
Захисник один

22

Майбутнє настало!

Підтримка налагодження лямбда-виразів додана до Visual Studio 2015 ( попередній перегляд на момент написання).

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


Це приємно бачити. Класно ...!
Рахул Нікате


5

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

Все найкраще, Патріку


5
Зауважте, що, хоча перше посилання виглядає неймовірно, воно має альфа-версію і, швидше за все, ніколи з нього не вийде (востаннє оновлено в 2008 році).
Джон Сальватьє,

2

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

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


Ну, вони можуть створювати методи; вони можуть створювати Expressionдерева - це залежить від контексту.
Марк Гравелл

1

У VS 2015 ви можете зробити це зараз, це одна з нових функцій, яку вони додали.


1

Якщо вам все-таки потрібно використовувати 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 \ ", column \ Odrani \ n \ Oderani \". оператор припинено. "} 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

Щоб відповісти на ваше запитання, ось офіційне пояснення менеджера програми Visual Studio, чому ви не можете цього зробити. Коротше кажучи, тому що "це дійсно, дуже важко" впровадити у VS. Але ця функція наразі триває (оновлена ​​в серпні 2014 року).

Дозволити оцінку лямбда-виразів під час налагодження

Додайте свій голос, поки ви там!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.