2012-07-03 30 views
11

Đây có thể là một câu hỏi cú pháp đơn giản, nhưng tôi không thể hiểu được.Thực hiện IEnumerable với một Array

Thông thường, tôi sẽ làm điều này:

public class OrderBook : IEnumerable<PriceLevel> 
{ 
    private readonly List<PriceLevel> PriceLevels = new List<PriceLevel>(); 

    public IEnumerator<PriceLevel> GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 

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

Nhưng thay vì một danh sách, tôi muốn sử dụng một mảng - như thế này:

public class ArrayOrderBook : IEnumerable<PriceLevel> 
{ 
    private PriceLevel[] PriceLevels = new PriceLevel[500]; 

    public IEnumerator<PriceLevel> GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 

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

Các IEnumerator IEnumerable.GetEnumerator() dường như biên dịch tốt - nhưng công chúng IEnumerator<PriceLevel> nói rằng tôi cần một số loại diễn viên - cách tốt nhất để làm điều này là gì?

William

+2

Tại sao? Tại sao sử dụng một mảng cho điều này? – Oded

+1

'Danh sách' được sao lưu bằng một mảng, do đó bạn không đạt được bất kỳ thứ gì, ngoại trừ việc làm quá mức công việc của bạn. – Tudor

+1

@Tudor tùy thuộc vào logic khác trong lớp, có thể có ý nghĩa hơn với 'PriceLevels' là một mảng (ví dụ: kích thước cố định). Không có gì sai với mong muốn tái cấu trúc đó. –

Trả lời

14

Hãy thử điều này:

public class ArrayOrderBook : IEnumerable<PriceLevel> 
{ 
    private PriceLevel[] PriceLevels = new PriceLevel[500]; 

    public IEnumerator<PriceLevel> GetEnumerator() 
    { 
     return PriceLevels.AsEnumerable().GetEnumerator(); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
     return PriceLevels.GetEnumerator(); 
    } 
} 
+1

Các loại có thể được suy ra. '.AsEnumerable()' hoạt động tốt. 'T []' thực hiện 'IEnumerable ', nhưng phương thức công khai của nó cho 'GetEnumerator' trả về một 'IEnumerator' được đánh máy yếu. –

+0

@TimS. Bạn hoàn toàn đúng! –

6

Như bạn có thể nhìn thấy từ IEnumerable<T> thực hiện của riêng bạn, bạn cần phải cung cấp cả một phiên bản chung chung và không chung chung của phương pháp để hoàn thành giao diện. Để làm điều này, vì các phương thức có cùng một chữ ký, một trong số chúng cần phải là một giao diện thực hiện rõ ràng. Trong trường hợp của List, phiên bản chung là một phương thức trong lớp và phiên bản không phải là chung chung là định nghĩa giao diện rõ ràng, vì phiên bản chung chung hữu ích hơn. Trong trường hợp của một mảng, nó đã có phiên bản không chung chung như việc triển khai thực hiện, và nó đã thêm phiên bản chung của phương thức trong một phiên bản tiếp theo. Để tránh thay đổi đột phá, thay vào đó, phiên bản chung là định nghĩa giao diện rõ ràng.

Có một số cách giải quyết vấn đề này. Dưới đây là ba cái đơn giản.

public IEnumerator<PriceLevel> GetEnumerator() 
{ 
    return PriceLevels.AsEnumerable().GetEnumerator(); 
} 


public IEnumerator<PriceLevel> GetEnumerator() 
{ 
    IEnumerable<PriceLevel> enumerator = PriceLevels; 
    return enumerator.GetEnumerator(); 
} 

public IEnumerator<PriceLevel> GetEnumerator() 
{ 
    return ((IEnumerable<PriceLevel>)PriceLevels).GetEnumerator() 
} 
+0

+1 cho câu trả lời toàn diện nhất. – phoog

4

Cast T[] đến IEnumerable<T> tương ứng:

public IEnumerator<PriceLevel> GetEnumerator() 
    { 
     return ((IEnumerable<PriceLevel>)PriceLevels).GetEnumerator(); 
    } 
2

Theo ECMA-335 phân vùng I, §8.9.1, một loại vector (mảng không gian duy nhất như T[]) thực hiện IList<T> mà ngụ ý rằng nó cũng thực hiện IEnumerable<T>. Tuy nhiên, việc triển khai các phương pháp là rõ ràng, vì vậy bạn cần phải sử dụng một trong các cách sau:

Tùy chọn 1: Chỉ cần sử dụng phân bổ ngầm mảng vào IList<T>.

private IList<PriceLevel> PriceLevels = new PriceLevel[500]; 

Tùy chọn 2: Để biến thành viên làm mảng và sử dụng phương pháp mở rộng AsEnumerable. Phương pháp mở rộng này sử dụng nhiệm vụ ngầm được hỗ trợ, thích hợp hơn khi sử dụng dàn diễn viên trực tiếp như (IEnumerable<PriceLevel>)PriceLevels.

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

Items cần tránh:

  1. Phương pháp Cast<T> giới thiệu một kiểm tra loại không cần thiết cho mỗi phần tử của mảng của bạn và nên tránh.
  2. Nếu bạn chỉ cần bao gồm các phần tử không null từ điều tra, bạn có thể sử dụng phương thức mở rộng OfType<T>. Nếu không, phương pháp này cũng giới thiệu một kiểm tra kiểu không cần thiết trên mỗi phần tử.
Các vấn đề liên quan