LINQ 표현식을 번역 할 때 C# 컴파일러가 SelectMany를 어떻게 선택합니까?
-
05-07-2019 - |
문제
enumerable.selectmany에는 4 개의 과부하 서명이 있습니다. 간단하게하기 위해 두 서명을 무시합니다. int 논쟁. 따라서 SelectMany에 대한 2 개의 서명이 있습니다.
public static IEnumerable<TResult> SelectMany<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TResult>> selector
)
public static IEnumerable<TResult> SelectMany<TSource, TCollection, TResult>(
this IEnumerable<TSource> source,
Func<TSource, IEnumerable<TCollection>> collectionSelector,
Func<TSource, TCollection, TResult> resultSelector
)
내 질문은 : C# 컴파일러가 LINQ 표현식을 확장 메소드로 변환 할 때 SelectMany를 선택하는 방법은 무엇입니까?
기본적으로 여러 가지가있는 경우 ~에서 LINQ 표현에는 SelectMany가 있습니다. 그러나 C# 컴파일러는 두 번째 서명 만 선택하는 것 같습니다. 첫 번째 서명은 사용되지 않습니다.
IEnumerable<int> en1 = Enumerable.Range(1, 3);
IEnumerable<double> en2 = new double[] { 1.0, 3.14 };
IEnumerable<string> en3 =
from i1 in en1
from i2 in en2
select (i1 * i2).ToString();
foreach (var i in en3)
{
Console.WriteLine(i);
}
반사기의 도움으로 위의 LINQ 표현이
en1.SelectMany<int, double, string>(delegate (int i1) {
return en2;
}, delegate (int i1, double i2) {
double CS$0$0000 = i1 * i2return CS$0$0000.ToString();
})
위의 예에는 3 가지 유형이 포함됩니다. 따라서 두 번째 SelectMany 서명을 선택하는 것이 합리적입니다. 그러나 아래의 예를 들어, 하나의 유형 만 관련되어 있지만 여전히 두 번째 서명을 선택합니다.
IEnumerable<int> en4 =
from i1 in en1
from i2 in Enumerable.Range(0, i1)
select i2;
다음으로 번역됩니다.
en1.SelectMany<int, int, int>(delegate (int i1) {
return Enumerable.Range(0, i1);
}, delegate (int i1, int i2) {
return i2;
})
따라서 LINQ 표현이 첫 번째 SelectMany 서명으로 변환 된 사례를 찾을 수 없습니다. 그런 경우가 있습니까?
첫 번째 SelectMany 서명이 사용되지 않으면 기능 프로그래밍에서 Monad의 바인드이기 때문에 존재합니까?
아마도 질문은 다음과 같습니다. 왜 우리는 SelectMany의 2 개의 서명이 있습니까?
감사.
해결책
C# 사양에 따르면 컴파일러는 SelectMany의 첫 번째 버전에 과부하 호출을 생성하지 않습니다. SelectMany의 첫 번째 버전은 목록 목록을 단일 플랫 목록으로 평평하게하는 데 유용합니다.
public IEnumerable<string> Example(IEnumerable<IEnumerable<string>> enumerable) {
return enumerable.SelectMany(x => x);
}
쿼리 표현식에는 강력한 동등이 없습니다.
자세한 내용은 C# 언어 사양의 7.15.2 절을 참조하십시오.
다른 팁
SelectMany의 2 개의 서명이있는 이유는 무엇입니까?
그래서 내 코드에서 첫 번째를 사용할 수 있습니다.
var orders = Customers.SelectMany(c => c.Orders)