Який найскладніший або найбільш неправильно зрозумілий аспект 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.