Как отладить оператор 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 и точно определить те, которые трудно перехватить в запросах.

Вот как ваш запрос будет выглядеть в 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.

Другие вопросы по тегам