2011-11-22 11 views
5

Tôi biết rất nhiều đã được viết về LINQ và hoạt động bên trong của nó. Lấy cảm hứng từ Jon Skeets EduLinq, tôi muốn làm sáng tỏ những gì đang diễn ra đằng sau các nhà khai thác LINQ. Vì vậy, những gì tôi đã cố gắng làm là để thực hiện Linqs Select() phương pháp mà âm thanh khá nhàm chán ngay từ cái nhìn đầu tiên. Nhưng những gì tôi thực sự cố gắng làm là triển khai nó mà không cần sử dụng từ khóa lợi nhuận.Triển khai LINQs Chọn không có từ khóa lợi nhuận. Không thể theo dõi luồng kiểm soát

Vì vậy, đây là những gì tôi có cho đến nay:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var list = new int[] {1, 2, 3}; 

     var otherList = list.MySelect(x => x.ToString()).MySelect(x => x + "test"); 

     foreach (var item in otherList) 
     { 
      Console.WriteLine(item); 
     } 

     Console.ReadLine(); 
    } 
} 

public static class EnumerableEx 
{ 
    public static IEnumerable<R> MySelect<T, R>(this IEnumerable<T> sequence, Func<T, R> apply) 
    { 
     return new EnumerableWrapper<R, T>(sequence, apply); 
    } 
} 

public class EnumerableWrapper<T, O> : IEnumerable<T> 
{ 
    private readonly IEnumerable<O> _sequence; 
    private readonly Func<O, T> _apply; 

    public EnumerableWrapper(IEnumerable<O> sequence, Func<O, T> apply) 
    { 
     _sequence = sequence; 
     _apply = apply; 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
     return new EnumeratorWrapper<T, O>(_sequence, _apply); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return GetEnumerator(); 
    } 
} 

public class EnumeratorWrapper<T, O> : IEnumerator<T> 
{ 
    private readonly IEnumerator<O> _enumerator; 
    private readonly Func<O, T> _apply; 

    public EnumeratorWrapper(IEnumerable<O> sequence, Func<O, T> apply) 
    { 
     _enumerator = sequence.GetEnumerator(); 
     _apply = apply; 
    } 

    public void Dispose() 
    { 
    } 

    public bool MoveNext() 
    { 
     var hasItems = _enumerator.MoveNext(); 
     if (hasItems) 
      Current = _apply(_enumerator.Current); 
     return hasItems; 
    } 

    public void Reset() 
    { 
     _enumerator.Reset(); 
    } 

    public T Current { get; private set; } 

    object IEnumerator.Current 
    { 
     get { return Current; } 
    } 
} 

Có vẻ như để làm việc. Tuy nhiên, tôi gặp khó khăn để theo dõi luồng điều khiển của nó. Như bạn có thể thấy, tôi chuỗi để chiếu. Điều này khiến cho những điều kỳ lạ (lạ đối với tôi!) Xảy ra trong phương thức MoveNext(). Nếu bạn thiết lập các điểm ngắt trong mỗi dòng của phương thức MoveNext(), bạn sẽ thấy rằng luồng điều khiển thực sự nhảy giữa các cá thể khác nhau và không bao giờ làm việc thông qua phương thức trong một lô. Nó nhảy như thể nó đang sử dụng các chủ đề khác nhau hoặc nếu chúng ta đang sử dụng năng suất. Nhưng cuối cùng, nó chỉ là một phương pháp bình thường vì vậy tôi tự hỏi những gì đang xảy ra ở đó?

Trả lời

5

Mỗi lần bạn gọi MoveNext() vào kết quả nó sẽ:

  • Gọi MoveNext() trên iterator thức (mà tôi sẽ gọi cho Y), mà sẽ ...
  • Gọi MoveNext() trên iterator trước (mà tôi sẽ gọi X), mà sẽ ...
  • Gọi MoveNext() trên bản gốc trình lặp (của mảng), sẽ trả về một số.
  • MoveNext() trong X sau đó sẽ gọi x => x.ToString() chiếu để nó có thích hợp Current viên
  • MoveNext() trong Y sau đó sẽ gọi cho chiếu x => x + "test" trên kết quả của X.Current, và lưu trữ kết quả trong Y.Current

Vì vậy, không có gì đặc biệt huyền diệu xảy ra ở đây - bạn vừa nhận được các cuộc gọi xếp chồng, giống như bình thường. Trải nghiệm gỡ lỗi sẽ cho bạn thấy cuộc gọi đó từ một số EnumeratorWrapper.MoveNext đến một cuộc gọi khác; chỉ nhảy lẻ xung quanh sẽ là khi bạn bước qua các phép chiếu, được khai báo trong phương thức Main.

Nếu điều đó không giải thích điều gì khiến bạn khó hiểu, vui lòng cung cấp thêm chi tiết về chính xác nơi bạn không hiểu luồng và tôi sẽ xem cách tôi có thể trợ giúp. (Thật tuyệt khi thấy bạn muốn tìm hiểu thêm về cách tất cả những điều này hoạt động. Tốt để thấy một tinh thần nhân hậu!)

+1

AAAAAAAAAAARG !! Chắc chắn rồi! Tôi bị mù! Nhân tiện, việc trả lời nhanh của bạn bất cứ lúc nào khiến tôi nghĩ rằng bạn đã viết một bot rất thông minh để trả lời tất cả những điều thông minh đó ;-) – Christoph

+0

@Christoph [Bài hát chủ đề X-Files] Chúng tôi chỉ có thể hy vọng rằng nó chỉ là "rất bot thông minh "... –