Что является самым сложным или наиболее неправильно понятым аспектом LINQ? [закрыто]


282

Справочная информация: В течение следующего месяца я буду выступать с тремя докладами, по крайней мере, в том числе LINQв контексте C#. Я хотел бы знать, на какие темы стоит обратить пристальное внимание, основываясь на том, что людям может быть трудно понять, или на что у них может быть ошибочное впечатление. Я не буду конкретно говорить о том, LINQчтобы SQLили в Entity Framework , за исключением примеров того , как запросы могут быть выполнены удаленно с помощью деревьев выражений (и обычно IQueryable).

Итак, что вы усердно нашли LINQ? Что вы видели с точки зрения недопонимания? Примерами могут быть любые из следующих, но, пожалуйста, не ограничивайте себя!

  • Как C#компилятор обрабатывает выражения запроса
  • Лямбда-выражения
  • Деревья выражений
  • Методы расширения
  • Анонимные типы
  • IQueryable
  • Отложено против немедленного исполнения
  • Потоковое и буферизованное выполнение (например, OrderBy откладывается, но буферизируется)
  • Неявно типизированные локальные переменные
  • Чтение сложных родовых подписей (например, Enumerable.Join )

3
Мне было бы интересно узнать, когда вы собираетесь проводить эти переговоры, и есть ли возможность просмотреть их в Интернете
Марк Хит,

2
Первое выступление: Копенгаген, 30 октября. Надеюсь, это будет записано на пленку. (Целый день!) Второй доклад: Лондон, 19 ноября вечером, Лондонская группа пользователей .NET, вероятно, на Push LINQ. Третий доклад: чтение, 22 ноября, день разработчика, внедрение LINQ для объектов за 60 минут.
Джон Скит

1
Downvoters: пожалуйста, добавьте пояснительный комментарий.
Джон Скит

2
@Jon, прости, но мне нужно это закрыть.
Тим Пост

3
@Tim: Достаточно справедливо - он все равно не получил больше ответов. Лично я думаю, что это в конечном итоге оказалось конструктивным, заметьте - мне, безусловно, было полезно посмотреть, что люди находят хитрым. Я бы, наверное, не спросил бы об этом сейчас ...
Джон Скит

Ответы:


271

Задержка исполнения


12
Право - это явно фаворит среди читателей, что является самым важным в этом вопросе. Я также добавлю «буферизацию против потоковой передачи» в миксы, поскольку это тесно связано - и часто не обсуждается так подробно, как хотелось бы видеть в книгах.
Джон Скит

10
В самом деле? Когда я изучал Linq, мне так много раз указывали на эту ленивую натуру, что для меня это никогда не было проблемой.
Адам Лассек

26
Согласитесь с ALassek. В документации MSDN четко указывается ленивый характер оценки LINQ. Может быть, настоящая проблема заключается в ленивом характере программирования разработчиков ... =)
Seiti

4
... особенно когда вы понимаете, что это относится к LINQ к объектам, а не только к LINQ 2 SQL - когда вы видите 10 вызовов веб-методов для получения списка элементов, когда вы уже перечисляете этот же список элементов, и вы подумали, что список уже был оценен
Simon_Weaver

5
Знание, что такое выражение yield и как оно работает, ИМХО крайне важно для полного понимания LINQ.
ПЕШИР

125

Я знаю, что концепция отложенного выполнения должна быть уже внедрена в меня, но этот пример действительно помог мне понять это на практике:

static void Linq_Deferred_Execution_Demo()
{
    List<String> items = new List<string> { "Bob", "Alice", "Trent" };

    var results = from s in items select s;

    Console.WriteLine("Before add:");
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }

    items.Add("Mallory");

    //
    //  Enumerating the results again will return the new item, even
    //  though we did not re-assign the Linq expression to it!
    //

    Console.WriteLine("\nAfter add:");
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }
}

Приведенный выше код возвращает следующее:

Before add:
Bob
Alice
Trent

After add:
Bob
Alice
Trent
Mallory

2
blogs.msdn.com/b/charlie/archive/2007/12/09/… <- я думаю, что это лучший блог, чтобы объяснить это, по моему мнению. (далеко за 2007, не могу поверить, что это уже так давно)
Филл

104

То есть больше , чем просто , LINQчтобы SQLи особенности больше , чем просто SQLсинтаксический анализатор , встроенный в языке.


6
Я устал от того, что все думают, что: /
TraumaPony

40
Не все так делают! Я до сих пор не знаю, что такое LINQ to SQL, и я все время использую LINQ.
Роберт Россни

2
Я так раздражаюсь, когда пытаюсь что-то объяснить, используя LINQ, а другой человек просто смотрит на меня и говорит: «О, я не использую LINQ для чего-то подобного, только SQL» :(
Натан W

13
Согласитесь, многие люди не понимают, что LINQ - это инструмент общего назначения.
Мэтью Оленик

86

Big O обозначения . LINQ позволяет невероятно легко писать O (n ^ 4) алгоритмов, не осознавая этого, если вы не знаете, что делаете.


16
Как насчет примера?
Hughdbrown

4
В качестве примера, возможно, он имеет в виду тот факт, что предложение Select очень легко содержит много операторов Sum (), каждый из которых вызывает еще один проход по всему набору записей.
Роб Пэквуд

1
На самом деле, возможно, стоит даже рассмотреть, что такое большая O-нотация и почему она важна, а также некоторые примеры неэффективных итоговых запросов. Я думаю, это то, что предлагал оригинальный постер, но я все же упомянул об этом. - РЕДАКТИРОВАТЬ: только что понял, что этому посту было 1,5 года :-)
zcrar70

7
Это не будет O (n ^ x), это будет O (xn), а это просто O (n).
Малфист

3
Попытка сделать соединение без оператора соединения приведет к O (n ^ x): от i1 в диапазоне1 от i2 в диапазоне 2 от i3 в диапазоне 3 от i4 в диапазоне 4, где i1 == i2 && i3 == i4 выберите новый {i1, i2, i3, i4}. И я на самом деле видел это написано раньше. Это работает, но очень медленно.
MarkPflug

55

Я думаю, что тот факт, что Lambdaвыражение может разрешаться как в дерево выражений, так и в анонимный делегат, позволяет передавать одно и то же декларативное lambdaвыражение как в IEnumerable<T>методы IQueryable<T>расширения, так и в методы расширения.


2
Согласовано. Я ветеран, и я только что понял, что это неявное приведение происходит, когда я начал писать свой собственный QueryProvider
TheSoftwareJedi

53

Взял меня путь слишком долго , чтобы понять , что многие методы расширения LINQ , такие как Single(), и SingleOrDefault()т.д. имеют перегрузки , которые принимают лямбды.

Ты можешь сделать :

Single(x => x.id == id)

и не нужно говорить это - что какой-то плохой учебник привел меня в привычку делать

Where(x => x.id == id).Single()

+1, очень мило. Я буду иметь это в виду.
крендель

4
Я продолжаю забывать и об этом. Это также относится Count()и к другим. Знаете ли вы, есть ли разница в производительности в дополнение к очевидному бонусу читабельности кода?
Джастин Морган

1
В университете мой преподаватель хотел снять баллы за использование этих перегрузок !! Я доказал его неправоту!
TDaver

12
Это может звучать странно, но я предпочитаю второй синтаксис. Я нахожу это более читабельным.
Конамиман

40

В LINQ to SQL я постоянно вижу людей, не понимающих DataContext, как его можно использовать и как его использовать. Слишком много людей не видят DataContext таким, какой он есть, объектом единицы работы, а не постоянным объектом.

Я много раз видел, как люди пытаются записать один DataContext / сеанс / и т. Д. Вместо того, чтобы устанавливать новое время для каждой операции.

Кроме того, существует возможность удаления DataContext до того, как IQueryable будет оценен, но это больше похоже на людей, не понимающих IQueryable, чем DataContext.

Другая концепция, с которой я часто путаюсь - это синтаксис запросов против синтаксиса выражений. Я буду использовать тот, который когда-либо был самым легким на тот момент, часто придерживаясь синтаксиса выражений. Многие люди до сих пор не понимают, что в конце концов они сделают то же самое, Query в конце концов скомпилирован в Expression.


2
Предупреждение. Единицей работы может быть небольшая программа с контекстом данных как синглтоном.
График

15
Вы не должны использовать DataContext в одиночном коде, это не потокобезопасно.
Аарон Пауэлл

3
@ Замените, не все программы являются многопоточными, поэтому вполне допустимо использовать DataContext в качестве единого элемента во многих «настольных» программах
Ян Рингроз

2
Это меня укусило (используя DataContext в качестве синглтона), когда я делал свой первый проект LINQ to SQL. Я не думаю, что документация и книги делают это достаточно очевидным. На самом деле, я думаю, что имя можно улучшить, но я не уверен, как.
Роджер Липскомб

1
Потребовалось несколько раз прочитать статьи Скотту на Линке, чтобы врезаться в мою голову.
Эван Плейс

34

Я думаю, что неправильно понятая часть LINQ заключается в том, что это расширение языка , а не расширение базы данных или конструкция.

LINQэто намного больше, чем LINQ to SQL.

Теперь, когда большинство из нас использовали LINQколлекции, мы никогда не вернемся!

LINQ является наиболее важной особенностью .NET начиная с Generics в 2.0 и Anonymous Types в 3.0.

И теперь, когда у нас есть лямбда, я не могу дождаться параллельного программирования!


Я бы даже назвал это более значимым, чем анонимные типы, и, возможно, даже больше, чем дженерики.
Джастин Морган

26

Я, конечно, хотел бы знать, нужно ли мне знать, что такое деревья выражений и почему.


6
Я думаю, что стоит знать, что такое деревья выражений и почему они существуют, а не детали того, как их строить самостоятельно. (Их сложно создавать вручную, но компилятор отлично справится с преобразованием лямбда-выражения.)
Джон Скит

3
На самом деле, я думал о создании нескольких записей в блоге на деревьях выражений (так как я их "получаю"). Я считаю манипулирование деревьями выражений очень полезным ...
Марк Гравелл

Тем не менее, я не думаю, что они будут полезны для выступлений Джона ;-p
Марк

3
Я просто волнуюсь, что деревья выражений будут похожи на выражение yield: что-то, что оказалось невероятно ценным, несмотря на то, что я сначала не понимал, для чего он нужен.
Роберт Россни

1
Марк Гравелл Я хотел бы прочитать ваши записи в блоге на эту тему. С нетерпением жду этого
Александр Brisebois

20

Я довольно новичок в LINQ. Вот вещи, на которые я наткнулся в своей первой попытке

  • Объединение нескольких запросов в один
  • Эффективная отладка LINQ-запросов в Visual Studio.

21
Отладка LINQ - тема сама по себе и важная. Я думаю, что самая большая слабость LINQ заключается в том, что он позволяет вам писать блоки произвольно сложной логики, через которую вы не можете пройти.
Роберт Россни

3
это может быть хорошим местом для использования LINQ pad
Maslow

2
Согласитесь от всей души; вот почему я написал LINQ Secrets Revealed: Chaining and Debugging , только что опубликованный на Simple-Talk.com, который может вам пригодиться.
Майкл Соренс

Да, LinqPad - отличный вторичный инструмент для разработки ваших запросов LINQ. Особенно, когда вы начинаете, и вы новичок в соглашениях / шаблонах.
Буффало

20

Что-то, чего я изначально не осознавал, было то, что синтаксис LINQ не требует IEnumerable<T>или не IQueryable<T>работает, LINQ - это просто сопоставление с образцом.

альтернативный текст http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png

Вот ответ (нет, я не писал этот блог, это сделал Барт Де Смет, и он один из лучших блогеров на LINQ, который я нашел).


1
Вы также можете найти этот пост интересным: msmvps.com/blogs/jon_skeet/archive/2008/02/29/…
Джон Скит

Хороший пост Джон (я подписался на ваш блог, хотя недавно).
Аарон Пауэлл

19

У меня все еще есть проблемы с командой "let" (которую я никогда не использовал) и SelectMany (которую я использовал, но я не уверен, что все сделал правильно)


2
Каждый раз, когда вы хотите ввести переменную, вы должны использовать оператор let. Подумайте о традиционном цикле, в котором вы вводите переменные внутри него и присваиваете каждой переменной имя, чтобы улучшить читаемость кода. Иногда также хорошо, когда у вас есть оператор let, оценивающий результат функции, который вы затем можете выбрать и упорядочить без необходимости дважды оценивать результат.
Роб Пэквуд

'let' позволяет вам делать составные типы. Удобные вещи.
Филл

19

Понимание, когда происходит утечка среди провайдеров Linq. Некоторые вещи работают с объектами, но не с SQL (например, .TakeWhile). Некоторые методы могут быть переведены в SQL (ToUpper), а другие нет. Некоторые методы более эффективны в объектах, где другие более эффективны в SQL (различные методы соединения).


1
Это очень хороший момент. Это не поможет, что Intellisense покажет вам ВСЕ из них, и он обычно даже компилируется. Затем вы взорвать во время выполнения. Я надеюсь, что VS 2010 лучше показывает соответствующие методы расширения.
Джейсон Шорт

12

Пара вещей.

  1. Люди думают о Linq как о Linq для SQL.
  2. Некоторые люди думают, что они могут начать заменять весь foreach / логику запросами Linq без учета этого влияния на производительность.

11

Хорошо, из-за спроса, я написал некоторые вещи Expression. Я не на 100% доволен тем, как блоггер и LiveWriter сговорились отформатировать его, но пока это подойдет ...

Во всяком случае, здесь идет ... Я хотел бы получить любую обратную связь, особенно если есть области, где люди хотят больше информации.

Вот оно , хочешь ты ненавидишь ...


10

Некоторые сообщения об ошибках, особенно из LINQ to SQL, могут быть довольно запутанными. усмешка

Я был укушен отсроченным исполнением пару раз, как и все остальные. Я думаю, что самой запутанной вещью для меня был поставщик запросов SQL Server и то, что вы можете и не можете с ним сделать.

Я все еще поражен тем фактом, что вы не можете использовать Sum () для столбца десятичной дроби / денег, который иногда пуст. Использование DefaultIfEmpty () просто не будет работать. :(


1
Должно быть, легко набросать a Где в этом запросе сделать сумму работы
Эсбен Сков Педерсен

9

Я думаю, что в LINQ важно упомянуть о том, как вы можете получить проблемы с производительностью. Например, использование счетчика LINQ в качестве условия цикла действительно не очень разумно.


7

То, что IQueryable принимает как, так Expression<Func<T1, T2, T3, ...>>и Func<T1, T2, T3, ...>без подсказки о снижении производительности во 2-м случае.

Вот пример кода, который демонстрирует, что я имею в виду:

[TestMethod]
public void QueryComplexityTest()
{
    var users = _dataContext.Users;

    Func<User, bool>                funcSelector =       q => q.UserName.StartsWith("Test");
    Expression<Func<User, bool>>    expressionSelector = q => q.UserName.StartsWith("Test");

    // Returns IEnumerable, and do filtering of data on client-side
    IQueryable<User> func = users.Where(funcSelector).AsQueryable();
    // Returns IQuerible and do filtering of data on server side
    // SELECT ... FROM [dbo].[User] AS [t0] WHERE [t0].[user_name] LIKE @p0
    IQueryable<User> exp = users.Where(expressionSelector);
}

Вы можете объяснить? Я не следую ...
Крендель

@Pretzel Я добавил пример кода, который демонстрирует мою проблему.
Валера Колупаев

Спасибо за пример кода! Очень полезно.
Буффало

6

Я не знаю, может ли это быть неправильно понято - но для меня просто неизвестно.

Мне было приятно узнать о DataLoadOptions и о том, как я могу контролировать, какие таблицы объединяются при выполнении определенного запроса.

Смотрите здесь для получения дополнительной информации: MSDN: DataLoadOptions


6

Я бы сказал, что наиболее недооцененным (или непонятным?) Аспектом LINQ является IQueryable и пользовательские поставщики LINQ .

Я уже некоторое время использую LINQ, и я полностью чувствую себя комфортно в мире IEnumerable, и могу решить большинство проблем с помощью LINQ.

Но когда я начал смотреть и читать о IQueryable, а также о Expressions и пользовательских linq-провайдерах, это заставило меня задуматься. Посмотрите, как работает LINQ to SQL, если вы хотите увидеть довольно сложную логику.

Я с нетерпением жду понимания этого аспекта LINQ ...


6

Как говорит большинство людей, я думаю, что наиболее неправильно понятая часть предполагает, что LINQ является просто заменой T-SQL. Мой менеджер, который считает себя гуру TSQL, не позволил бы нам использовать LINQ в нашем проекте и даже ненавидит MS за то, что выпустил такую ​​вещь !!!


Слишком много людей используют его как замену TSQL. Большинство из них никогда не слышали о плане выполнения.
erikkallen

+1, потому что я согласен с вашим менеджером, по крайней мере, если разрешить LINQ to SQL в любом проекте. LINQ to Objects - это совсем другое дело.
NotMe

5

Что представляет собой var при выполнении запроса?

Является ли это iQueryable, iSingleResult, iMultipleResultили делает это меняется в зависимости от реализации. Есть некоторые предположения об использовании (как представляется) динамической типизации по сравнению со стандартной статической типизацией в C #.


AFAIK var всегда является конкретным классом, о котором идет речь (даже если это анонимный тип), поэтому он никогда не будет IQueryable, ISingleResult или чем-либо, начинающимся с «I» (конкретные классы, начинающиеся с «I», применять не нужно).
Мотти

5

Насколько легко вкладывать петли, я не думаю, что все это понимают.

Например:

from outerloopitem in outerloopitems
from innerloopitem in outerloopitem.childitems
select outerloopitem, innerloopitem

+1, воу. это довольно мощно.
крендель

4

group by все еще заставляет мою голову кружиться.

Любая путаница с отложенным выполнением должна быть разрешена путем пошагового выполнения некоторого простого кода на основе LINQ и воспроизведения в окне просмотра.


1
Я обнаружил, что реализация небольшого количества LINQ to Objects для развлечения действительно помогает :) Но да, это немного сбивает с толку - конечно, если я некоторое время не делал LINQ, мне нужно вернуться к сигнатурам. Точно так же "присоединяйся" против "присоединяйся к" часто получает меня ...
Джон Скит

4

Скомпилированные запросы

Тот факт, что вы не можете объединить в цепочку, IQueryableпотому что они являются вызовами методов (хотя это все еще не что иное, как переводимый SQL!) И что практически невозможно обойти это, ошеломляет и создает огромное нарушение DRY. Мне нужны мои IQueryableспециальные, в которых у меня нет скомпилированных запросов (я только скомпилировал запросы для тяжелых сценариев), но в скомпилированных запросах я не могу их использовать, и вместо этого мне нужно снова написать обычный синтаксис запроса. Сейчас я делаю одни и те же подзапросы в 2 местах, нужно помнить, что нужно обновлять, если что-то меняется, и так далее. Кошмар.


4

Я думаю, что ошибочное представление № 1 о LINQ to SQL заключается в том, что вы ДОЛЖНЫ ЗНАТЬ SQL, чтобы эффективно его использовать.

Еще одно неправильное понимание Linq to Sql заключается в том, что вам все равно придется понизить безопасность базы данных до абсурда, чтобы заставить ее работать.

Третий момент заключается в том, что использование Linq to Sql вместе с динамическими классами (то есть определение класса создается во время выполнения) приводит к огромному количеству своевременной компиляции. Который может абсолютно убить производительность.


4
Однако очень полезно знать SQL. Некоторый SQL, который излучается Linq to SQL (и другими ORM), может быть весьма сомнительным, и знание SQL помогает диагностировать такие проблемы. Кроме того, Linq to SQL может использовать хранимые процедуры.
Роберт Харви


2

Как уже упоминалось, ленивая загрузка и отложенное выполнение

Чем LINQ to Objects и LINQ to XML (IEnumerable) отличаются от LINQ to SQL (IQueryable)

КАК построить уровень доступа к данным, бизнес-уровень и уровень представления с LINQ на всех уровнях .... и хороший пример.


Первые два я могу сделать. Я не хотел бы пытаться сделать третий еще в смысле «это правильный путь»
Джон Скит

+1, пока вы не указали на это, я не осознавал, что LINQ-to-Objects и LINQ-to-XML были IEnumerable в отличие от LINQ-to-SQL как IQueryable, но это имеет смысл. Спасибо!
крендель

2

Как говорит большинство людей, я думаю, что наиболее неправильно понятая часть предполагает, что LINQ является просто заменой T-SQL. Мой менеджер, который считает себя гуру TSQL, не позволил бы нам использовать LINQ в нашем проекте и даже ненавидит MS за то, что выпустил такую ​​вещь !!!


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.