Как отладить оператор LINQ
У меня есть заявление Linq для объектов
var confirm = from l in lines.Lines
where (l.LineNumber == startline.LineNumber) || (l.LineNumber == endline.LineNumber)
select l;
Объект подтверждения возвращает 'Нулевой объект или нет ссылки' в System.Linq.Enumerable.WhereListIterator`1.MoveNext().
Если бы результат запроса был пустым, он просто вернул бы пустой перечислитель. Я точно знаю, что в заявлении нет нулевых объектов. Можно ли пройти через оператор LINQ, чтобы увидеть, где он падает?
РЕДАКТИРОВАТЬ Когда я сказал, что знаю, что нет нулевых объектов, оказалось, что я лгал: [, но вопрос остается, хотя я предполагаю, что ответ будет "вы не можете на самом деле"
LINQPad - хорошая идея, я использовал ее, чтобы научить себя LINQ, но я могу начать смотреть на нее снова как на инструмент для отладки, слэша и записи.
10 ответов
Я не уверен, что можно отладить в VS, но я считаю, что LINQPad весьма полезен. Это позволит вам выводить результаты каждой части запроса LINQ.
Да, действительно возможно приостановить выполнение на полпути через запрос linq.
Преобразуйте ваш linq в стиль запроса, используя лямбда-выражения, и вставьте оператор Select, который возвращает себя где-то после точки в linq, которую вы хотите отладить. Некоторый пример кода сделает его более понятным -
var query = dataset.Tables[0].AsEnumerable()
.Where (i=> i.Field<string>("Project").Contains("070932.01"))
// .Select(i =>
// {return i;}
// )
.Select (i=>i.Field<string>("City"));
Затем раскомментируйте закомментированные строки. Убедитесь, что {return i;} находится в отдельной строке и вставьте туда точку отладки. Вы можете поместить этот выбор в любой момент длинного и сложного запроса linq.
Вы должны иметь возможность установить точку останова для выражения в where
пункт вашего заявления LINQ.
В этом примере поместите курсор в любом месте следующего раздела кода:
(l.LineNumber == startline.LineNumber) || (l.LineNumber == endline.LineNumber)
Затем нажмите F9 или используйте меню или контекстное меню, чтобы добавить точку останова.
При правильной настройке только приведенный выше код должен иметь форматирование точки останова в редакторе, а не весь оператор LINQ. Вы также можете посмотреть в окне контрольных точек, чтобы увидеть.
Если вы установили его правильно, вы будете каждый раз останавливаться на функции, которая реализует вышеуказанную часть запроса.
Я написал исчерпывающую статью по этому вопросу, опубликованную на Simple-Talk.com (" Секреты LINQ: раскрытие цепочек и отладка") еще в 2010 году:
Я говорю о LINQPad (как упоминалось ранее OwenP) как о отличном инструменте, внешнем по отношению к Visual Studio. Обратите особое внимание на его необычный метод Dump(). Вы можете добавить это в одну или несколько точек в цепочке LINQ, чтобы ваши данные были удивительно чистыми и понятными. Хотя LINQPad очень полезен, он является внешним по отношению к Visual Studio. Поэтому я также представляю несколько методов, доступных для использования в Visual Studio, потому что иногда просто не практично переносить кусок кода в LINQPad:
(1) Внедрить вызовы метода расширения Dump(), который я представляю в своей статье, чтобы разрешить ведение журнала. Я начал с метода Bart De Smet's Watch() в его информативной статье LINQ to Objects - Debugging и добавил некоторые надписи и раскраски для улучшения визуализации, хотя он по-прежнему бледнеет по сравнению с выводом дампа LINQPad.
(2) Добавьте визуализацию LINQPad прямо в Visual Studio с помощью надстройки Роберта Иванка LINQPad Visualizer. Не уверен, что это было из-за моего подталкивания:-), но пара неудобств, которые присутствовали, когда я писал свою статью, теперь все замечательно устранены в последней версии. Он имеет полную поддержку VS2010 и позволяет вам исследовать любой объект, который вам нравится при отладке.
(3) Вставьте операторы nop в середину цепочки LINQ, чтобы вы могли устанавливать точки останова, как описано ранее Amazing Pete.
2016.12.01 Обновление
И я только что написал продолжение вышеприведенной статьи под названием " Отладка и визуализация LINQ", которое показывает, что настоящая возможность отладки LINQ наконец-то появилась в Visual Studio 2015 с новой функцией, которая должна быть выпущена в OzCode. Ответ Дрора на этот вопрос показывает мельчайший проблеск этого, но я призываю вас прочитать мою новую статью для углубленного "как". (И я не работаю на OzCode.:-)
[Отказ от ответственности: я работаю в OzCode]
Проблема с LINQ заключается в том, что отладку трудно или невозможно - даже при работе с простыми запросами разработчик вынужден реорганизовать свой запрос в группу циклов foreach или использовать ведение журнала. Отладка LINQ поддерживается в версии OzCode, которая скоро выйдет (в настоящее время доступна в качестве предварительного просмотра раннего доступа), и помогает разработчикам также углубиться в свой код LINQ и точно определить те, которые трудно перехватить в запросах.
Можно войти внутрь выражения LINQ без установки каких-либо временных точек останова. Вам нужно войти в функцию, которая оценивает выражение LINQ, например:
var confirm = from l in lines.Lines
where (l.LineNumber == startline.LineNumber)
|| (l.LineNumber == endline.LineNumber)
select l;
confirm.ToArray(); // Press F11 ("Step into") when you reach this statement
foreach(var o in q) // Press F11 when "in" keyword is highlighted as "next statement"
// ...
Проверьте трассировку стека исключений и посмотрите, какой последний бит вашего кода был выполнен.
Судя по ошибкам, я бы посоветовал вам взглянуть на line.Lines и убедиться, что его перечислитель реализован правильно. Я думаю, что это возвращает ноль, когда это не должно.
Да, и просто убедитесь, что объекты line и line.Lines не равны NULL или не возвращают NULL.
Чтобы выполнить оператор LINQ, просто поставьте точку останова на оператор linq, а затем, когда он начнет отлаживать эту строку, щелкните ее правой кнопкой мыши, выберите параметр «Выполнить до курсора». Он начнет выполнять код построчно, как обычно.
Хотя это не способ отладки, я бы предложил использовать следующее:
using (var db = new AppContext())
{
db.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
// Rest of code
}
Затем вы можете проверить окно вывода при отладке, чтобы увидеть SQL, сгенерированный из вашего запроса LINQ.