Який найскладніший або найбільш неправильно зрозумілий аспект LINQ? [зачинено]


282

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

Отже, що вам важко було LINQ? Що ви бачили з точки зору непорозумінь? Приклади можуть бути будь-якими з наведених нижче, але будь ласка, не обмежуйте себе!

  • Як C#компілятор обробляє вирази запитів
  • Лямбда-вирази
  • Вираження дерев
  • Методи розширення
  • Анонімні типи
  • IQueryable
  • Відкладено проти негайного виконання
  • Потокове та буферне виконання (наприклад, OrderBy відкладений, але буферний)
  • Логічні змінні, що невдало вводять
  • Читання складних загальних підписів (наприклад, Enumerable.Join )

3
Мені було б цікаво дізнатися, коли ви збираєтесь вести ці переговори, і якщо є якийсь спосіб їх перегляду в Інтернеті
Марк Хіт,

2
Перша розмова: Копенгаген, 30 жовтня. Сподіваємось, це буде записано на запис. (Цілий день!) Друга розмова: Лондон, 19 листопада ввечері, Лондон .NET Group Group, напевно, на Push LINQ. Третя розмова: Читання, 22 листопада, День розробника для розробників, впровадження LINQ до об'єктів за 60 хвилин.
Джон Скіт

1
Користувачі: додайте пояснювальний коментар.
Джон Скіт

2
@Jon, Вибач, але мені потрібно це закрити.
Тім Пост

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

Відповіді:


271

Затримка виконання


12
Righto - це, очевидно, улюблений серед читачів, що є найважливішим у цьому питанні. Я також додаю "буферизацію проти потоку" в суміш, оскільки це тісно пов'язано - і часто не обговорюється так детально, як хотілося б бачити в книгах.
Джон Скіт

10
Дійсно? У мене було так, що ця лінива природа вказувала на мене стільки разів під час навчання Лінка, це ніколи не було проблемою для мене.
Адам Лассек

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

4
... особливо коли ви розумієте, що це стосується LINQ до об'єктів, а не лише до LINQ 2 SQL - коли ви бачите 10 викликів веб-методів для отримання списку елементів, коли ви вже перераховуєте цей самий список елементів, і ви думали, що Список вже був оцінений
Simon_Weaver

5
Знання, що таке декларація про врожайність та як вона працює, є критичним для глибокого розуміння LINQ.
peSHIr

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 для SQL, і я використовую LINQ весь проклятий час.
Роберт Россні

2
Мене це дратує, коли я намагаюся пояснити щось за допомогою LINQ, а інша людина просто дивиться на мене і каже: "Ой, я не використовую LINQ для чогось подібного, тільки SQL" :(
Nathan W

13
За згодою, багато людей, здається, не розуміють, що LINQ - це інструмент загального призначення.
Матвій Оленік

86

Big O нотації . LINQ дозволяє неймовірно легко писати алгоритми O (n ^ 4), не усвідомлюючи цього, якщо ви не знаєте, що робите.


16
Як щодо прикладу?
hughdbrown

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

1
Насправді, можливо, варто переглядати, що таке велика нотація O і чому вона важлива, а також кілька прикладів неефективних результатів запитів. Я думаю, що це запропонував оригінальний плакат, але я думав, що все одно це згадаю. - EDIT: щойно зрозумів, що цій посаді було 1,5 року :-)
zcrar70

7
Це не було б O (n ^ x), це було б O (xn), а це просто O (n).
Malfist

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 до SQL я постійно бачу людей, які не розуміють DataContext, як ним можна користуватися та як його використовувати. Забагато людей не бачать DataContext для того, що це таке, об'єкт "Unit of Work", а не постійний об'єкт.

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

А потім є розпорядження DataContext до того, як IQueryable буде оцінено, але це більше прихильність до людей, які не розуміють IQueyable, ніж DataContext.

Інша концепція, з якою я бачу велику плутанину, - це синтаксис запитів проти синтаксису виразів. Я використовую те, що коли-небудь найпростіше на той момент, часто дотримуючись синтаксис виразів. Дуже багато людей досі не усвідомлюють, що вони зроблять те саме, врешті-решт, Запит запитується в Expression.


2
Попередження: одиницею роботи може бути невелика програма з контекстом даних як одиночна.
graffic

15
Не слід використовувати DataContext в одиночному режимі, це не безпечно для потоків.
Аарон Пауелл

3
@Slace, не всі програми багатоголові, тому добре, щоб DataContext був одиночним у великій кількості "настільних" програм
Ian Ringrose

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

1
Потрібно читати артилети Скотга на Linq кілька разів, щоб це стукнуло мені в голову.
Еван Плейс

34

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

LINQце набагато більше, ніж LINQ to SQL.

Тепер, коли більшість з нас використовували LINQколекції, ми НІКОЛИ не повернемося!

LINQ є найбільш важливою особливістю для .NET з часу Generics в 2.0, а Anonymous Types в 3.0.

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


Я б навіть назвав це більш значущим, ніж анонімні типи, а можливо, навіть більше, ніж генеричні.
Джастін Морган

26

Я напевно хотів би знати, чи потрібно мені знати, що таке дерева виразів і чому.


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

3
Власне, я думав про те, щоб зробити кілька записів у блогах на деревах виразів (оскільки я їх "отримую"). Я вважаю, що маніпулювати деревами виразів дуже корисно ...
Marc Gravell

Однак я не вважаю, що вони можуть бути корисними для розмов Джона
;-p

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

1
Марк Гравелл. Я хотів би прочитати ваші записи в блозі на цю тему. З нетерпінням чекаю цього
Олександр Брісбуа

20

Я досить новачок у LINQ. Ось речі, на які я натрапив у першій спробі

  • Поєднання декількох запитів в один
  • Ефективно налагодження LINQ-запитів у Visual Studio.

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

3
це може бути хорошим місцем для використання накладки LINQ
Маслоу

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

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

20

Те, що я спочатку не усвідомлював, - це те, що синтаксис LINQ не вимагає IEnumerable<T>або IQueryable<T>не працює, LINQ - це лише відповідність шаблону.

alt text http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png

Ось відповідь (ні, я не писав цього блогу, Барт Де Смет зробив, і він один з найкращих блогерів на LINQ, який я знайшов).


1
Можливо, ця публікація в блозі також буде цікавою: msmvps.com/blogs/jon_skeet/archive/2008/02/29/…
Jon Skeet

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

19

У мене все ще виникають проблеми з командою «дозволити» (яку я ніколи не знаходив для використання) та SelectMany (яку я використав, але я не впевнений, що зробив це правильно)


2
Кожен раз, коли ви хочете ввести змінну, ви б використовували оператор let. Подумайте про традиційний цикл, куди ви вводите змінні всередині нього і даєте ім’я кожної змінної, щоб допомогти читати код. Іноді також непогано, коли у вас є оператор дозволу, що оцінює результат функції, який ви можете потім вибрати та замовити, не потребуючи оцінювання результату двічі.
Роб Паквуд

'Let' дозволяє робити складені типи. Зручні речі.
Філ

19

Розуміння, коли абстракція серед постачальників Linq протікає. Деякі речі працюють на об'єктах, але не на SQL (наприклад, .TakeWhile). Деякі методи можуть бути переведені в SQL (ToUpper), а інші не можуть. Деякі методи ефективніші в об'єктах, де інші ефективніші в SQL (різні методи з'єднання).


1
Це дуже вдалий момент. Це не допоможе, що Intellisense покаже вам ВСІ з них, і він зазвичай навіть компілюється. Тоді ви підриваєте під час виконання. Я сподіваюся, що VS 2010 виконує кращу роботу щодо показу відповідних методів розширення.
Jason Short

12

Пару речей.

  1. Люди думають про Linq як Linq для SQL.
  2. Деякі люди думають, що вони можуть почати замінювати всі foreach / логіки запитами Linq, не враховуючи наслідків цієї продуктивності.

11

Гаразд, через попит, я написав деякі матеріали з Expression. Я не на 100% задоволений тим, як блогер і LiveWriter змовились його форматувати, але це робитиму зараз ...

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

Ось це , подобається або ненавидить ...


10

Деякі повідомлення про помилки, особливо від LINQ до SQL, можуть бути досить заплутаними. усмішка

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

Я все ще вражений тим, що ви не можете зробити суму () на десятковій / грошовій колонці, яка іноді порожня. Використання DefaultIfEmpty () просто не працюватиме. :(


1
Потрібно бути легким, щоб легко ляпнути "Де" на цьому запиті, щоб зробити суму роботи
Есбен Сков Педерсен

9

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


7

Цей IQueryable приймає і те, Expression<Func<T1, T2, T3, ...>>і інше, Func<T1, T2, T3, ...>не даючи натяку на погіршення продуктивності у другому випадку.

Ось приклад коду, який демонструє, що я маю на увазі:

[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 до SQL, якщо ви хочете побачити досить складну логіку.

Я з нетерпінням чекаю розуміння цього аспекту LINQ ...


6

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


Занадто багато людей використовують його як заміну для TSQL. Більшість із них ніколи не чули про план розстрілу.
erikkallen

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

5

Що означає var, коли виконується запит?

Є чи це iQueryable, iSingleResult, iMultipleResultабо робить це змінюється в залежності від реалізації. Існує певна спекуляція щодо використання (як видається) динамічного набору тексту та стандартного статичного набору тексту в C #.


AFAIK var - це завжди конкретний клас, про який йде мова (навіть якщо це анонімний тип), тому це ніколи не IQueryable, ISingleResult або щось, що починається з 'I' ​​(конкретні класи, що починаються з 'я', не потрібно застосовувати).
Мотті

5

Як легко вкласти петлю - це те, що я не думаю, що всі розуміють.

Наприклад:

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

+1, хто. це досить потужно.
Кредзель

4

group by все ще змушує мою голову крутитися.

Будь-яку плутанину щодо відкладеного виконання слід вирішити, перейшовши через простий код на основі LINQ і погравши у вікно годинника.


1
Я виявив, що реалізація LINQ в об'єктах для розваги справді допомагає :) Але так, це дещо заплутано - звичайно, якщо я не робив жодного LINQ деякий час, я повинен повернутися до підписів. Так само "приєднуйся" до "приєднуйся" часто мене змушує ...
Джон Скіт

4

Складені запити

Той факт, що ви не можете ланцюжок, IQueryableтому що це виклики методів (в той час як все ще нічого, крім SQL-перекладної!), І що майже неможливо обійти це, є розумним глухою і створює величезне порушення DRY. Мені потрібні мої IQueryableрекламні матеріали для спеціальних запитів, у яких я не збираю запити (я складаю лише запити для важких сценаріїв), але в складених запитах я не можу їх використовувати і замість цього потрібно знову писати синтаксис регулярних запитів. Зараз я роблю ті самі підзапити в 2-х місцях, потрібно пам’ятати, щоб оновити і те, якщо щось зміниться, і так далі. Кошмар.


4

Я думаю, що помилковим уявленням №1 щодо LINQ для SQL є те, що ВИ ВЖЕ ЗНАЄТЕ ЗНАТИ SQL, щоб ефективно використовувати його.

Ще одна неправильно зрозуміла річ щодо Linq - Sql - це те, що вам все одно доведеться знизити безпеку бази даних до абсурду, щоб змусити її працювати.

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


4
Однак дуже корисно вже знати SQL. Деякі SQL, які випускає Linq в SQL (та інші ORM), можуть бути дуже сумнівними, і знання SQL допомагає діагностувати подібні проблеми. Крім того, Linq до SQL можуть використовувати збережені процедури.
Роберт Харві


2

Як згадувалося, ліниве завантаження і відкладене виконання

Наскільки LINQ для об'єктів і LINQ до XML (IEnumerable) відрізняються від LINQ до SQL (IQueryable)

ЯК створити рівень доступу до даних, бізнес-шар та шар презентацій за допомогою LINQ у всіх шарах .... і хороший приклад.


Перші два я можу зробити. Я не хотів би намагатися робити третій ще в сенсі "це правильний спосіб зробити це" ...
Джон Скіт

+1, поки ви цього не вказали, я не зрозумів, що LINQ до об'єктів і LINQ до XML є безліч, на відміну від LINQ до SQL, як IQueryable, але це має сенс. Дякую!
Кредзель

2

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


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