LINQ의 가장 어렵거나 오해 된 부분은 무엇입니까? [닫은]


282

배경 : 다음 달에, 나는 적어도 LINQ에 관한 내용을 포함 해서 적어도 세 번의 연설을 할 것 입니다 C#. 사람들이 이해하기 어려울 수있는 부분 또는 잘못된 인상을 받았을 수있는 주제에 따라 어느 정도의 관심을 기울일 가치가 있는지 알고 싶습니다. 내가 특별히 얘기하지 않습니다 LINQSQL제외 쿼리가 원격으로 (보통과 표현의 나무를 사용하여 실행 할 수있는 방법의 예로 또는 엔티티 프레임 워크 IQueryable).

그래서 무엇에 대해 열심히 찾았 LINQ습니까? 오해의 관점에서 무엇을 보았습니까? 예는 다음 중 하나 일 수 있지만 자신을 제한하지 마십시오!

  • C#컴파일러가 쿼리 표현식을 처리 하는 방법
  • 람다 식
  • 표현 트리
  • 확장 방법
  • 익명 유형
  • IQueryable
  • 지연된 대 즉시 실행
  • 스트리밍 vs 버퍼 실행 (예 : OrderBy가 지연되었지만 버퍼링 됨)
  • 암시 적으로 입력 된 지역 변수
  • 복잡한 일반 서명 읽기 (예 : Enumerable.Join )

3
이 대화를 언제 할 것인지, 온라인에서 볼 수있는 방법이 있는지 알고 싶습니다.
Mark Heath

2
첫 번째 대화 : 10 월 30 일 코펜하겐. 잘만되면 이것이 녹화 될 것입니다. (전일!) 두 번째 대화 : 11 월 19 일 런던, 런던 .NET 사용자 그룹, 아마도 Push LINQ에 관한 것입니다. 세 번째 강의 : 읽기, 11 월 22 일, 개발자 개발자의 날, 60 분 안에 LINQ to Objects 구현.
Jon Skeet

1
Downvoters : 설명을 추가하십시오.
Jon Skeet

2
@Jon, 죄송하지만 이걸 닫아야합니다.
Tim Post

3
@Tim : 충분히 공평합니다-더 이상 답을 얻지 못했습니다. 개인적으로 내가 생각 했던 건설되고 결국, 당신 마음 - 나는 확실히 사람들이 어려운 찾을 것을 볼 수 유용하다고. 아마 지금은 묻지 않았을 것입니다 ...
Jon Skeet

답변:


271

실행 지연


12
Righto-이것은 독자들 사이에서 가장 좋아하는 것입니다.이 질문에 가장 중요한 것입니다. 또한 "버퍼링 vs 스트리밍"을 믹스에 추가 할 것입니다. 이는 밀접하게 관련되어 있으며 종종 책에서보고 싶은만큼 자세히 다루지 않습니다.
Jon Skeet

10
정말? Linq를 배우는 동안 게으른로드 된 자연이 나에게 여러 번 지적 했으므로 결코 문제가되지 않았습니다.
Adam Lassek

26
ALassek에 동의하십시오. MSDN 설명서에는 LINQ의 느린 평가 특성이 명시되어 있습니다. 아마도 실제 문제는 개발자의 게으른 프로그래밍 특성 일 것입니다 ... =)
Seiti

4
... 특히 LINQ 2 SQL이 아닌 객체에 LINQ에 적용된다는 것을 알고있을 때-동일한 항목 목록을 이미 열거하고 있고 항목을 이미 열거했을 때 10 개의 웹 메소드 호출로 항목 목록을 검색하는 경우 이미 평가되었습니다
Simon_Weaver 5

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 년까지, 이미 그렇게 오래 지속되었다고 믿을 수 없음)
Phill

104

이 단지보다 더 많은 것을 LINQSQL와 기능은 더 단지보다 SQL언어에 포함 된 파서.


6
나는 모든 사람들이 다음과 같은 생각을하는 것에 아프다 : /
TraumaPony

40
모두가 아닙니다! 나는 여전히 LINQ to SQL이 무엇인지 알지 못하고 LINQ를 항상 사용합니다.
Robert Rossney

2
나는 그래서 나는 시도하고 LINQ 그냥 나를보고 말한다 다른 사람이 사용하는 무언가를 설명 할 때 짜증 "오 내가 그런 아무것도 LINQ를 사용하지 않는를 만 SQL":(
나단 W

13
많은 사람들은 LINQ가 범용 도구라는 것을 이해하지 못하는 것 같습니다.
Matthew Olenik

86

큰 O 표기법 . LINQ를 사용하면 수행중인 작업을 모르는 경우 O (n ^ 4) 알고리즘을 구현하지 않고도 매우 쉽게 작성할 수 있습니다.


16
예는 어떻습니까?
hughdbrown

4
예를 들어, 그는 Select 절에 많은 Sum () 연산자가 포함되어있어 전체 레코드 집합을 다시 통과하게하는 것이 매우 쉽다는 것을 의미합니다.
Rob Packwood

1
실제로 큰 O 표기법이 무엇이며 왜 중요한지, 비효율적 인 결과 쿼리의 예를 살펴볼 가치가 있습니다. 나는 그것이 원래의 포스터가 제안한 것이라고 생각하지만 어쨌든 나는 그것을 언급 할 것이라고 생각했다. -편집 : 그냥이 게시물이 1.5 세임을 깨달았습니다 :-)
zcrar70

7
그것은 O (n ^ x)가 아니고 O (xn)입니다. 이것은 단지 O (n)입니다.
Malfist

3
조인 연산자없이 조인을 시도하면 O (n ^ x)가 발생합니다. i2, i3, i4}. 그리고 저는 실제로이 글을 전에 보았습니다. 작동하지만 매우 느립니다.
MarkPflug

55

Lambda식이 식 트리와 익명 대리자 둘 다로 해석 될 수 있으므로 동일한 선언식 lambdaIEnumerable<T>확장 메서드와 IQueryable<T>확장 메서드 모두에 전달할 수 있다고 생각합니다 .


2
동의했다. 나는 베테랑 그리고 난 그냥 내 자신의 QueryProvider 쓰기 시작으로이 암시 적 캐스팅이 일어나고 실현
TheSoftwareJedi

53

나를 툭 방법 등 많은 LINQ 확장 방법을 실현하는 데 시간이 너무 오래 Single(), SingleOrDefault()등이 람다을 과부하가 있습니다.

넌 할 수있어 :

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

이것을 말할 필요가 없습니다-나쁜 튜토리얼로 인해 습관이 생겼습니다.

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

+1, 아주 좋습니다. 명심하겠습니다.
Pretzel

4
나는 이것을 잊어 버린다. 또한 Count()다른 것들 중에서도 마찬가지입니다 . 코드 가독성의 명백한 보너스 외에도 성능 차이가 있는지 알고 있습니까?
저스틴 모건

1
대학에서 강사는 이러한 과부하 사용에 대한 포인트를 빼고 싶었습니다 !! 나는 그를 잘못 증명했다!
TDaver

12
이상하게 들릴지 모르지만 두 번째 구문을 선호합니다. 더 읽기 쉽습니다.
Konamiman

40

LINQ to SQL에서 나는 DataContext를 이해하지 못하는 사람들, 그것을 어떻게 사용할 수 있고 어떻게 사용해야 하는지를 끊임없이 봅니다. 너무 많은 사람들이 지속성 오브젝트가 아닌 작업 단위 오브젝트가 무엇인지 DataContext를 보지 못합니다.

사람들이 각 작업에 대해 새로운 시간을 만드는 대신 DataContext / 세션 / 세션 등을 싱글 톤하려고하는 많은 시간을 보았습니다.

그런 다음 IQueryable을 평가하기 전에 DataContext를 폐기하지만 사람들은 DataContext보다 IQueryable을 이해하지 못하는 경향이 있습니다.

내가 혼동하는 다른 개념은 Query Syntax vs Expression Syntax입니다. 그 시점에서 가장 쉬운 것을 사용하고 종종 Expression Syntax를 사용합니다. 많은 사람들이 여전히 똑같은 결과물을 만들어 낼 것이라는 것을 아직 모르고 있습니다. Query는 결국 Expression으로 컴파일됩니다.


2
경고 : 작업 단위는 데이터 컨텍스트가 싱글 톤 인 소규모 프로그램 일 수 있습니다.
graffic

15
단일 컨텍스트에서 DataContext를 사용하면 안되며 스레드로부터 안전하지 않습니다.
Aaron Powell

3
@Slace, 모든 프로그램이 멀티 헤드되지는 않으므로 많은 "데스크톱"소프트웨어에서 DataContext를 싱글 톤으로 사용하는 것이
좋습니다

2
첫 번째 LINQ to SQL 프로젝트를 수행했을 때 (DataContext를 싱글 톤으로 사용하여) 물었습니다. 나는 문서와 책이 이것을 충분히 분명히한다고 생각하지 않습니다. 사실, 나는 이름이 향상 될 수 있다고 생각하지만 어떻게 확신 할 수 없습니다.
Roger Lipscombe

1
Linq에서 ScottGu의 기사를 여러 번 읽는 것이 내 머리에 두들겨졌습니다.
Evan Plaice

34

내 생각 LINQ의 오해 부분이 그것이라는 것이다 언어 확장 이 아닌 데이터베이스 확장 또는 구조.

LINQ이상 LINQ to SQL입니다.

이제 대부분의 사람들이 LINQ컬렉션 을 사용 했으므로 다시는 돌아 가지 않을 것입니다!

LINQ 2.0의 Generics와 3.0의 Anonymous Types 이후 .NET에서 가장 중요한 단일 기능입니다.

그리고 이제 Lambda가 있으므로 병렬 프로그래밍을 기다릴 수 없습니다!


나는 심지어 익명 형식보다 더 중요하고 제네릭보다 더 중요하다고 부릅니다.
저스틴 모건

26

나는 표현 트리가 무엇인지, 왜 필요한지 알아야합니다.


6
표현 트리가 무엇이고 왜 존재하는지 아는 것이 가치가 있다고 생각하지만 직접 작성하는 방법에 대한 세부 사항은 아닙니다. (수동으로 빌드하기는 쉽지 않지만 컴파일러는 람다 식을 변환 할 때 훌륭한 작업을 수행합니다.)
Jon Skeet

3
실제로, 나는 표현 트리에 대해 몇 가지 블로그 항목을 생각하고 있었다 (왜냐하면 그것들을 "얻기"때문이다). 나는 표현 트리 조작이 매우 유용하다는 것을 알았습니다 ...
Marc Gravell

그러나 나는 그들이 존의 대화에 도움이되지 않는다고 생각합니다. ;-p
Marc Gravell

3
나는 표현 트리가 항복 진술과 같을 것이라고 걱정합니다. 처음에는 그것이 무엇인지 이해하지 못했지만 믿을 수 없을만큼 가치있는 것으로 밝혀졌습니다.
Robert Rossney

1
Marc Gravell 주제에 대한 블로그 항목을 읽고 싶습니다. 그것을 기대
Alexandre Brisebois

20

LINQ를 처음 사용합니다. 첫 시도에서 우연히 만난 것이 여기 있습니다.

  • 여러 쿼리를 하나로 결합
  • Visual Studio에서 LINQ 쿼리를 효과적으로 디버깅합니다.

21
LINQ 디버깅은 그 자체로 중요한 주제입니다. LINQ의 가장 큰 약점은 단계적으로 수행 할 수없는 임의의 복잡한 논리 블록을 작성할 수 있다는 것입니다.
Robert Rossney

3
이러한 사용 LINQ 패드에 좋은 장소가 될 수 있습니다
매스로 우는

2
진심으로 동의하십시오. 이것이 바로 Simple-Talk.com에 게시 된 LINQ Secrets Revealed : Chaining and Debugging을 작성한 이유 입니다.
Michael Sorens

예. LinqPad는 LINQ 쿼리를 개발하는 데 유용한 보조 도구입니다. 특히 시작시 컨벤션 / 패턴을 처음 사용하는 경우.
버팔로

20

내가 실현 원래하지 않았다 무언가는 LINQ 구문이었다 하지 않습니다 필요 IEnumerable<T>또는 IQueryable<T>작업에 LINQ 그냥 패턴 매칭에 관한 것입니다.

대체 텍스트 http://bartdesmet.info/images_wlw/QIsIQueryabletheRightChoiceforMe_13478/image_thumb_3.png

여기에 답이 (아니, 내가 하지 않은 그 블로그를 작성, 바트 드 스멧는했다, 그는 LINQ 내가 한 FOUND에서 최고의 블로거 중 하나).


1
당신도이 블로그 게시물 흥미를 찾을 수 있습니다 msmvps.com/blogs/jon_skeet/archive/2008/02/29/...을
존 소총을

좋은 게시물 Jon (최근에 한해 블로그를 구독하고 있습니다).
Aaron Powell

19

"let"명령 (사용한 적이없는) 및 SelectMany (사용한 적이 있지만 올바르게 수행했는지 확실하지 않음)에 여전히 문제가 있습니다.


2
변수를 도입하려고 할 때마다 let 문을 사용합니다. 내부에 변수를 도입하고 각 변수에 이름을 지정하여 코드의 가독성을 높이는 전통적인 루프를 생각해보십시오. 때로는 함수 결과를 평가하는 let 문이있는 경우에도 좋으며, 결과를 두 번 평가하지 않고도 선택하여 순서를 지정할 수 있습니다.
Rob Packwood

'let'을 사용하면 복합 유형을 수행 할 수 있습니다. 편리한 물건.

19

Linq 공급자 간의 추상화가 언제 유출되는지 이해합니다. SQL에서는 작동하지 않지만 객체에서는 작동하는 것이 있습니다 (예 : .TakeWhile). 일부 메소드는 SQL (ToUpper)로 변환 될 수 있지만 다른 메소드는 그렇지 않습니다. 일부 기법은 다른 기법이 SQL (다른 조인 방법)에서보다 효과적인 개체에서 더 효율적입니다.


1
이것은 매우 좋은 지적입니다. Intellisense가 모든 것을 보여주고 일반적으로 컴파일하는 데 도움이되지 않습니다. 그런 다음 런타임에 폭파합니다. VS 2010이 관련 확장 방법을 더 잘 보여주기를 바랍니다.
Jason Short

12

몇 가지.

  1. Linq를 Linq to SQL로 생각하는 사람들.
  2. 어떤 사람들은 이러한 성능 영향을 고려하지 않고 모든 foreach / logic을 Linq 쿼리로 교체 할 수 있다고 생각합니다.

11

좋아, 수요 때문에, 나는 표현 재료 중 일부를 작성했습니다. 블로거와 LiveWriter가 어떻게 형식을 정립했는지에 대해 100 % 만족 스럽지는 않지만 지금은 그렇게 할 것입니다 ...

어쨌든, 여기에 간다 ... 나는 특히 사람들이 더 많은 정보를 원하는 영역이 있다면 의견을 듣고 싶습니다.

여기가 맘에 들어요


10

LINQ에서 SQL 로의 일부 오류 메시지는 매우 혼란 스러울 수 있습니다. 이를 드러내고 웃다

나는 다른 사람들처럼 두 번이나 연기 된 처형에 물렸다. 가장 혼란스러운 부분은 SQL Server Query Provider와 함께 할 수 있고 할 수없는 일이라고 생각합니다.

때로는 비어있는 소수 / 돈 열에서 Sum ()을 수행 할 수 없다는 사실에 여전히 놀랐습니다. DefaultIfEmpty ()를 사용하면 작동하지 않습니다. :(


1
어디 메이크업 합 작업에 해당 쿼리에 때리는 쉽게 prette을 마땅한
Esben SKOV 페데르센

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

@Pretzel 내 문제를 보여주는 코드 예제를 추가했습니다.
Valera Kolupaev

코드 예제에 감사드립니다! 매우 도움이됩니다.
버팔로

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

적어도 모든 프로젝트에서 LINQ to SQL을 허용하는 한 관리자와 동의하기 때문에 +1입니다. LINQ to Objects는 전적으로 또 다른 문제입니다.
NotMe

5

쿼리가 실행될 때 var는 무엇을 나타 냅니까?

그것은인가 iQueryable, iSingleResult, iMultipleResult, 또는 않는 그것은 구현에 따라 변경. C #에서 동적 타이핑을 사용하는 것과 표준 정적 타이핑을 사용하는 것에 대한 추측이 있습니다.


AFAIK의 VAR는 항상 그래서 문제의 콘크리트 클래스 (이 익명 타입의 경우에도)는 결코 된 IQueryable, ISingleResult 또는 아무것도가 '나는'( 'I'필요로 시작 구체적인 클래스가 적용되지 않음)로 시작합니다.
Motti

5

루프를 중첩하는 것이 얼마나 쉬운지는 모든 사람들이 이해하지 못하는 것입니다.

예를 들면 다음과 같습니다.

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

+1, 우와 꽤 강력합니다.
Pretzel

4

group by 여전히 내 머리를 돌립니다.

지연된 실행 에 대한 혼동은 간단한 LINQ 기반 코드를 단계별로 살펴보고 조사 식 창에서 재생하여 해결할 수 있어야합니다.


1
나는 약간의 LINQ to Objects를 재미있게 구현하는 것이 실제로 도움이된다는 것을 발견했습니다.) 그러나 그렇습니다. 약간의 혼란이 있습니다. 마찬가지로 "join"대 "join into"는 종종 저를 가져옵니다.
Jon Skeet

4

컴파일 된 쿼리

IQueryable메소드 호출이기 때문에 체인 할 수 없다는 사실 ( 아직 SQL을 번역 할 수는 없지만) 해결하기가 거의 불가능하다는 사실은 혼란스럽고 DRY를 크게 위반합니다. 나는 IQueryable쿼리를 컴파일하지 않은 ad-hoc (필요한 시나리오에 대해서만 쿼리를 컴파일 했음)이 필요하지만 컴파일 된 쿼리에서는 사용할 수 없으며 대신 일반 쿼리 구문을 다시 작성해야합니다. 이제 두 곳에서 동일한 하위 쿼리를 수행하고 있으며 변경 사항이있는 경우 두 가지를 모두 업데이트해야합니다. 악몽.


4

LINQ to SQL에 대한 # 1 오해는 SQL을 효과적으로 사용하기 위해 여전히 알고 있어야한다는 것입니다.

Linq to Sql에 대해 잘못 이해 한 또 다른 사실은 데이터베이스 보안을 작동하기 위해 부실한 지점으로 데이터베이스 보안을 낮추어야한다는 것입니다.

세 번째 요점은 Linq to Sql을 동적 클래스와 함께 사용하면 (런타임에 클래스 정의가 생성됨을 의미) 엄청난 양의 JIT (Just-In-Time) 컴파일이 발생한다는 것입니다. 절대적으로 성능을 저하시킬 수 있습니다.


4
그러나 SQL을 이미 알고있는 것이 좋습니다. Linq가 SQL (및 다른 ORM)로 방출하는 일부 SQL은 매우 모호 할 수 있으며 SQL을 아는 것은 이러한 문제점을 진단하는 데 도움이됩니다. 또한 Linq to SQL은 저장 프로 시저를 사용할 수 있습니다.
Robert Harvey


2

언급 한 바와 같이 지연로드 및 지연된 실행

LINQ to Objects와 LINQ to XML (IEnumerable)이 LINQ to SQL (IQueryable)과 다른 점

모든 계층에서 LINQ를 사용하여 데이터 액세스 계층, 비즈니스 계층 및 프레젠테이션 계층을 구축하는 방법 과 좋은 예.


내가 할 수있는 첫 두 가지. 나는 "이것이 옳은 방법이다"라는 의미에서 세 번째를하고 싶지는 않습니다.
Jon Skeet

+1, 당신이 그것을 지적 할 때까지, 나는 LINQ-to-Objects와 LINQ-to-XML이 IQueryable과 같은 LINQ-to-SQL과 반대로 IEnumerable이라는 것을 알지 못했지만 말이됩니다. 감사!
Pretzel

2

대부분의 사람들이 말했듯이, 가장 오해 된 부분은 LINQ가 T-SQL의 대체품이라고 가정합니다. 자신을 TSQL 전문가로 생각하는 관리자는 우리 프로젝트에서 LINQ를 사용하지 못하게하고 심지어 MS를 싫어하여 그러한 것을 발표했습니다!


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.