2012-07-03 10 views
11

これは簡単な構文質問ですが、わかりません。配列でIEnumerableを実装する

通常、私はこれだろう。

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

をしかし、リストの代わりに、私は配列を使用したい - このように:

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

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

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

IEnumerator IEnumerable.GetEnumerator()罰金コンパイルするようだ - しかし、公開IEnumerator<PriceLevel>は、私は何らかのキャストが必要だと言います - これを行う最善の方法は何ですか?

ウィリアム

+2

なぜですか?なぜこのための配列を使用するのですか? – Oded

+1

'List'は配列自体でバックアップされているので、あなたの仕事が過度に複雑になることを除いて、何も得られません。 – Tudor

+1

@ Tudorクラス内で他のロジックがどのようになっているかによって、PriceLevelsが配列(固定サイズなど)になると意味があります。それをリファクタリングしたいとは何も間違っていません。 –

答えて

14

はこれを試してみてください:

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

タイプが推測できます。 '.AsEnumerable()'はうまくいきます。 'T []'は 'IEnumerable 'を実装しますが、 'GetEnumerator'のpublicメソッドは弱く型付けされた' IEnumerator'を返します。 –

+0

@TimS。あなたは絶対に正しいです!最も包括的な答えは –

6

あなたがあなた自身のIEnumerable<T>実装から見ることができるように、あなたはインターフェイスを達成する方法の一般的な非ジェネリック版の両方を提供する必要があります。これを行うには、メソッドのシグネチャが同じであるため、そのうちの1つが明示的なインタフェース実装である必要があります。 Listの場合、汎用バージョンはクラス内のメソッドであり、非汎用バージョンは一般的にはより有用であるため、非汎用バージョンは明示的なインターフェース定義です。配列の場合は、既に非ジェネリック版が実装されており、後続バージョンにメソッドのジェネリック版が追加されています。この変更を回避するために、汎用バージョンは代わりに明示的なインターフェイス定義です。

この問題を解決するにはいくつかの方法があります。ここには3つの単純なものがあります。対応IEnumerable<T>

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です。 – phoog

4

キャストT[]

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

ECMA-335パーティションI、§8.9.1、ベクトル型(T[]ような1次元配列)によれば、それことを意味IList<T>実装しますIEnumerable<T>も実装しています。ただし、メソッドの実装は明示的なので、次のいずれかを使用する必要があります。

オプション1:配列の暗黙の割り当てをIList<T>に使用するだけです。

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

オプション2:配列としてメンバ変数のままにし、AsEnumerable拡張メソッドを使用します。この拡張メソッドは、(IEnumerable<PriceLevel>)PriceLevelsのような直接キャストを使用するよりも望ましい、暗黙の割り当てをサポートしています。避けるために

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

アイテム:

  1. Cast<T>方法は、あなたの配列の各要素には不要な型チェックを紹介し、避けるべきです。
  2. 列挙からnull以外の要素のみを含める必要がある場合は、OfType<T>拡張メソッドを使用しても問題ありません。それ以外の場合、このメソッドは各要素の不要な型チェックも導入します。
関連する問題