2009-12-07 6 views
1

일부 사용자 지정 개체에 LINQ 인터페이스를 추가하고 있지만 C# compiler fails on type inference입니다. 그러나 원시 확장 메서드와 형식 유추를 사용하여 동일한 쿼리를 작성할 수 있으므로 컴파일러가 쿼리 식을 확장 메서드 호출로 변환하는 방법을 잘 모르겠습니다.LINQ 쿼리 식 변환기?

컴파일러가 내 쿼리 표현식에서 생성하는 내용을 볼 수 있도록 도구 나 컴파일러 플래그가 있습니까?

이 코드는 오픈 소스 프로젝트에 있으므로 도움이 될만한 곳으로 링크를 제공 할 수 있습니다. 확장 메서드의 형식 시그니처에 약간의 변형이이 형식 유추 오류를 피할 수 있지만 이러한 변형은 내가 의미하는 의미가 없습니다.

+2

컴파일러가 쿼리 식을 변환하는 데 사용하는 정확한 일련의 단계는 인터넷에서 얻을 수있는 C# 사양에 있습니다. –

답변

4

조회 이해의 코드는 다음과 같습니다

from f1 in e1 
from f2 in e2 
from f3 in e3 
select f3 

귀하의 메서드 호출 코드는 다음과

e1 
.SelectMany(f1 => e2) 
.SelectMany(f2 => e3), (f2, f3) => f3)) 

쿼리 번역을 진행한다. 먼저 우리는 절에서 처음 두 처리 :

from f1 in e1 
from f2 in e2 
from f3 in e3 
select f3; 

이이

"x"는 투명한 식별자
from x in (e1) . SelectMany(f1 => e2 , (f1 , f2) => new { f1 , f2 }) 
from f3 in e3 
select f3; 

로 변환됩니다. e1, e2 또는 e3 중 어느 것도 범위 변수를 사용하지 않으므로이 식별자가 투명한 식별자라는 사실은 부적절합니다. 투명 식별자 의미를 처리하기 위해 더 이상의 재 작성을 수행 할 필요가 없습니다. 분명히 이것은 당신이 수동으로 수행 한 구문 변환, 리콜에서 오히려 다른

e1 
.SelectMany(f1 => e2 , (f1 , f2) => new { f1 , f2 })) 
.SelectMany(x => e3 , (x , f3) => f3) 

을 :

결과는 다음

((e1) . SelectMany(f1 => e2 , (f1 , f2) => new { f1 , f2 })) 
.SelectMany(x => e3 , (x , f3) => f3) 

로 변환되는 것을 우리는 그 괄호의 일부를 제거 할 수 있습니다 ,이었다

e1 
.SelectMany(f1 => e2) 
.SelectMany(f2 => e3), (f2, f3) => f3)) 

귀하의 e1, e2, e3을 실제 위의 구문 론적 변환은 결과 표현식의 패스 유형 유추를 수행합니까?

그렇지 않으면 질문은 "왜 안 되니?"입니다. 코드에 문제가 있거나 유형 유추자가 잘못되었습니다. 유형 유추 자에게 문제가있는 경우 알려주십시오.

그렇다면 질문은 "구문 변환 통과에 어떤 문제가 있습니까?" 구문 변환 변환에 문제가있는 경우 다시 알려주십시오.

감사합니다.

+0

그런데 익명 형식이 이제 미래에 캡슐화되기 때문에 f1과 f2는 범위에 포함되지 않습니다. – naasking

+0

확장 메소드에 대한 약간의 조정으로 번역을 사용하면 f3을 반환 할 때 쿼리가 올바르게 컴파일되지만 f1과 f2는 더 이상 범위를 벗어납니다. 문제는 내가 해제 된 미래 유형에서 작동하고 있으며 클라이언트 코드에서 미래의 값만 추출하려고합니다. 그래서 일반적으로 SelectMany 보이는 같은 : 미래 SelectMany (이 미래 푸웃, Func을 > SEL, Func을 고해상도) 그러나 나는 그것을 같이해야합니다 미래 SelectMany (이 미래 푸웃, Func을 , 미래 > SEL , Func , 미래 , 미래 > res) 생각들? – naasking

+0

는 사실, 충분 다음 미래 SelectMany (이 미래 푸웃, Func을 , 미래 > SEL, Func을 , 미래 , R> 입술) 이 중 하나가 작동하지 않습니다. – naasking

1

Reflector을 사용하고 최적화가 해제 된 코드를 볼 수 있습니다.

+0

아니요, 쿼리 표현식의 코드가 컴파일되지 않았으므로 검토 할 항목이 없습니다. 나는 쿼리 표현식의 소스 코드를 동등한 확장 메서드를 사용하여 소스 코드로 변환하는 몇 가지 도구/기법을 찾고 있는데, 쿼리식이 컴파일되지 않는 이유를 알 수 있습니다. – naasking

+0

코드를 게시 할 수 있습니까? 아마도 내가보기에 나는 당신이 무슨 일이 일어나는지 알아낼 수 있도록 도와 줄 수 있습니다. –

+0

확장 메서드가있는 핵심 클래스, SelectMany는 427 줄 이상에서 정의됩니다. http://sasa.svn.sourceforge.net/viewvc/sasa/trunk/Sasa/Futures.cs?revision=416&view=markup 테스트를 참조하십시오. line 93 메서드 "testLinqSuccess"에 대한 오류 설명 : http://sasa.svn.sourceforge.net/viewvc/sasa/trunk/Build/Tests/FutureTests.cs?revision=416&view=markup 약간 더 많은 배경 : 미래를 사용한 비동기 계산입니다. 내 첫 번째 버전은 이전 모범 사례가 실패한 경우 모든 후속 미래가 실패한 오류 모나드처럼 작동했지만 원하는 의미가 아닙니다. 나는 어떤 통찰력을 주셔서 감사합니다. – naasking

0

Eric의 개요를 통해 이러한 쿼리가 어떻게 처리되는지 알 수있었습니다. 문제는 쿼리 변환이 좋아하지 않는 방식으로 조작되는 유형을 제한하려고 시도했기 때문입니다.

from x in Foo.Bar() 
... 

푸.Bar()는 Future를 반환하기로되어 있었고 x 또한 Future 형식으로되어 있었지만 쿼리 변환에는 작동하지 않습니다. 기본적으로 선물을 래핑하는 간접 참조를 추가하여이 문제를 해결했습니다. 예를 들어 Async <T> 유형은 미래로만 인스턴스화 될 수 있습니다.

public sealed class Async<T> { internal T value; } 
public static class Async 
{ 
    public static Async<Future<T>> Begin<T>(Future<T> future) { ... } 
} 

는 그럼 난 비동기 값에 대한 쿼리 계산을 쓸 수 있기 때문에 표현과 같이된다 : x는 유형의 미래 지금 내가 강제로 또는 선물을 연기 임의로 약속 할 수있는

from x in Async.Begin(Foo.Bar()) 
... 

합니다.

제안 해 주셔서 감사합니다. Visual Studio에 내장 된 쿼리 식 변환기는 좋지만 MS의 누군가가 이것을 읽는 경우에 유용합니다. ;-)