2009-01-08 53 views
9

Có 4 chữ ký quá tải cho Enumerable.SelectMany. Để đơn giản, chúng tôi bỏ qua hai chữ ký với đối số int. Vì vậy, chúng tôi có 2 chữ ký cho SelectMany:Trình biên dịch C# chọn SelectMany như thế nào khi dịch biểu thức LINQ?

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âu hỏi của tôi là: cách trình biên dịch C# chọn SelectMany khi dịch biểu thức LINQ sang lời gọi phương thức mở rộng?

Về cơ bản, nếu có nhiều từ trong biểu thức LINQ, sẽ có SelectMany. Nhưng, có vẻ như trình biên dịch C# chỉ chọn chữ ký thứ hai. Chữ ký đầu tiên không bao giờ được sử dụng.

 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); 
     } 

Với sự giúp đỡ của Reflector, tôi có thể thấy rằng trên biểu thức LINQ được dịch sang

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(); 
    }) 

Ví dụ ở trên bao gồm 3 loại. Vì vậy, nó là hợp lý để chọn chữ ký SelectMany thứ hai. Tuy nhiên, đối với ví dụ dưới đây, chỉ có một loại có liên quan, nó vẫn chọn chữ ký thứ hai.

 IEnumerable<int> en4 = 
      from i1 in en1 
      from i2 in Enumerable.Range(0, i1) 
      select i2; 

Nó được dịch thành:

en1.SelectMany<int, int, int>(delegate (int i1) { 
     return Enumerable.Range(0, i1); 
    }, delegate (int i1, int i2) { 
     return i2; 
    }) 

Vì vậy, tôi không thể tìm thấy một trường hợp đó biểu thức LINQ được dịch sang chữ ký SelectMany đầu tiên. Có trường hợp như vậy không?

Nếu chữ ký SelectMany đầu tiên không được sử dụng, thì nó tồn tại chỉ vì nó là BIND của đơn nguyên trong lập trình hàm?

Có lẽ câu hỏi có thể là: tại sao chúng ta có 2 chữ ký của SelectMany?

Cảm ơn.

Trả lời

5

Theo C# Spec, trình biên dịch sẽ không tạo ra một cuộc gọi quá tải đến phiên bản đầu tiên của SelectMany. Phiên bản đầu tiên của SelectMany rất hữu ích cho việc san phẳng danh sách các danh sách thành một danh sách phẳng đơn.

public IEnumerable<string> Example(IEnumerable<IEnumerable<string>> enumerable) { 
    return enumerable.SelectMany(x => x); 
} 

Nó không có tương đương mạnh trong biểu thức truy vấn.

Xem Phần 7.15.2 của Thông số ngôn ngữ C# để biết thêm thông tin.

+1

Thực sự ... hàm void trả về nội dung nào đó và không ai nhận xét về nó? –

5

tại sao chúng ta có 2 chữ ký của SelectMany?

Vì vậy, tôi có thể sử dụng mã đầu tiên trong mã của mình.

var orders = Customers.SelectMany(c => c.Orders) 
+0

Chắc chắn. Đó chỉ là để thuận tiện. –

+3

Chữ ký đầu tiên của SelectMany là đồng nhất với toán tử "liên kết" đơn điệu, được viết >> = trong Haskell. Một lý do nó được đưa vào là để củng cố nền tảng của LINQ trên khuôn khổ của các monads. Nền tảng đó làm cho LINQ đa hình có thể áp dụng cho tất cả mọi thứ như tuyên truyền nhà nước tổng hợp, ngoại lệ, tiếp tục, lựa chọn thay thế, v.v.: tất cả các monads. Xem http://en.wikipedia.org/wiki/Monad_(functional_programming). –

Các vấn đề liên quan