2016-04-30 7 views
1

私はC#の初心者プログラマーです。IEnumerableを使用するエクササイズに取り掛かりました。IEnumerableをメソッドの戻り値の型またはコンストラクタとして使用する理由

私は、コードを理解すると思うが、私は

.....次孤立コードを検討し、あなたが今までにこのよう

例1

それを使用する理由を理解するのに苦労しています

private List<Card> cards; 

public Deck (IEnumerable<Card> initialCards) 
{ 
    cards = new List<Card>(initialCards); 
} 

デッキオブジェクトを作成し、このコンストラクタがある呼び出すコード...

Card[] cardArray = new Card[numberOfCards]; 
for (int i = 0; i < numberOfCards; i++) 
{ 
    cardArray[i] = new Card((Suits)random.Next(0, 4), (Values)random.Next(0, 12)); 
} 
deck1 = new Deck(cardArray); 

誰かが最初に以下の私の理解を確認する気にしないだろう場合は...

  • 我々は型カードの配列を作成し、我々は[]カードでデッキコンストラクタに配列を渡すカード
  • でそれを埋めますDeckオブジェクトを作成するときに使用します。コンストラクタの引数にIEnumerable型のパラメータが含まれていても、配列がIEnumerableを実装しているので有効です。 ここでキャストが起こっていますか?
  • リストカードは、オーバーロードされたリストコンストラクタに渡されるIEnumerable引数で初期化されます。 もう一度、これは何かのキャストか変換ですか?

中間形式としてIEnumerableを使用することは全く意味がないようです。コードはまだ私は、コンストラクタを変更した場合、最終的に使用されているforeachループ...これは同じクラスのメソッドである2

public IEnumerable<string> GetCardNames() 
{ 
    string[] stringArray = new string[cards.Count]; 
    for (int i = 0; i < stringArray.Length; i++) 
    { 
     stringArray[i] = cards[i].ToString(); 
    } 
    return stringArray; 
} 

public Deck (Card [] initialCards) 
{ 
    cards = new List<Card>(initialCards); 
} 

例を含め、同じ作品。繰り返しますが、文字列配列に対してforeachを実行できるときにIEnumerableとして返される理由がわかりません。

例3

public IEnumerable<IWebElement> ElementCollection { get; set; } 

これは非常にnoobishですが、誰かが、これは何を言っているか私に説明できますか? IEnumerable型のパブリックプロパティですか?インターフェイスをプロパティタイプとして使用すると、他のタイプとはどのように異なるのですか?例えば文字列

これはコードの後半でLINQで使用されていますが、これはまだ学習には至りません。この例では、IEnumerableを何かを反復したいだけであれば使えるのでしょうか?

多くのおかげで、

+0

列挙型は、配列操作の一般化です。これらの操作には、配列によって提供されるもののサブセットが含まれます。すべての配列(またはリスト)*は* IEnumerableを実装します。 – user2864740

答えて

4

インターフェイスを返す(この場合はIEnumerable)か、それを受け入れることは、オブジェクト指向プログラミングの1つのコアアプローチです。これはOOPの3つのコア原則、特に抽象化を混在させます。

長期サポートアプリケーションでは、しばしば変更を行います。アプリケーションの開始時には、Cardコレクションの固定サイズが必要なので、配列を使用します。あなたがCardコレクションの非固定サイズに移動する必要がある時点で

private Card[] cards; 

public Deck (Card[] initialCards) 
{ 
    cards = initialCards; 
} 

。だから、あなたはあまりにもCardListを持って、あなたのアプリケーションの一部ではList

private List<Card> cards; 

public Deck (Card [] initialCards) 
{ 
    cards = new List<Card>(initialCards); 
} 

に移動します。それをコンストラクタに渡したいとします。それはいけません!内部構造がListであっても、コンストラクタは引き続き配列(Card[])を受け入れます。

Listを配列に変換するには、この外部部品が必要です。これを行うには、すべてのリストを繰り返し処理して、メモリ内の新しい構造(カードの配列)を作成する必要があります。あなたのデッキが何百万枚ものカードを持っていれば高価になる可能性があります。

つまり、あなたのアプリケーションが成長するいくつかの点でList

private List<Card> cards; 

public Deck (List<Card> initialCards) 
{ 
    cards = initialCards; 
} 

を受け入れるようにコンストラクタを変更します。ユニークなカードでゲームをする必要があります。アプリケーションの一部でHashSetのカードが作成されます。コンストラクタに渡すことはできません。悪いコンストラクタはListを受け入れています。 HashSetを受け入れるようにコンストラクタを変更すると、アプリケーションの別の部分からロジックが破られ、Listに渡されます。

アプリケーションの2つの部分から同じ方法でHashSetまたはListのいずれかを渡したい場合は、このコレクションを取得してそれを内部構造に割り当てるだけです。

あなたが本当に必要とするのは、foreachになる可能性のあるCardsのコレクションをとり、別の使用方法のために後で列挙することです。次に、アプリケーションの他の部分に伝えるだけです。「みんな、列挙できるオブジェクトを与えてください。SetList、またはArrayのいずれかが本当に気にしません。

private IEnumerable<Card> cards; 

public Deck (IEnumerable<Card> initialCards) 
{ 
    cards = initialCards; 
} 

他の点で同じです。複雑さを軽減します。あなたはあなたの消費者に、Cardのコレクションを列挙するように伝えるだけです。彼らはそれをリストし、いくつかのカード名を見る必要があります。名前を変更したり、新しいカードなどを追加したりする必要はありません。

実装の詳細は公開していません。あなたは、内部構造の理解を最小限にして、使用するオブジェクトに機会を与えるだけです。この情報を隠すこの方法は、カプセル化の一部として見つけることができます。

1

例1

は、我々は型カードの配列を作成し、カード

ない質問が、正しいとそれを埋めます。

Deckオブジェクトを作成するときに、Card []配列をDeckコンストラクタに渡します。コンストラクタ引数には、IEnumerable型のパラメータ が含まれていますが、配列の実装では IEnumerableと見なされます。ここでキャストが起こっていますか?

これは暗黙のキャストタイプです。タイプが 'そのタイプ'なので、タイプがインターフェースを実装するとき、ダウンキャストする必要はありません。たとえば、キウイフルーツのすべての特性を持っているため、キウイフルーツについて話しているすべての人が「キウイ」と「フルーツ」を区別する必要はありません。

リストカードは、オーバーロードされたリストコンストラクタに で渡されたIEnumerable引数で初期化されます。繰り返しますが、これは何かのキャストか 変換ですか?

チェックすると、リストにはIEnumerableコンストラクタが含まれます。コンストラクタにIEnumerableが渡されると、IEnumerableを別のIEnumerableに変換するためのキャストは必要ありません。

中間型としてIEnumerableを使用することは完全に意味がないようです。コードはまだ最終的に私がする...

public Deck (Card [] initialCards) 
{ 
    cards = new List<Card>(initialCards); 
} 

コンストラクタを変更する場合には、送信しようとする任意のコードを壊すこれにコンストラクタを変更し、無意味ではありません使用されているforeachループを含め、同じように動作します代わりにコンストラクタをリストします。

例2

public IEnumerable<string> GetCardNames() 
{ 
    string[] stringArray = new string[cards.Count]; 
    for (int i = 0; i < stringArray.Length; i++) 
    { 
     stringArray[i] = cards[i].ToString(); 
    } 
    return stringArray; 
} 

これは、同じクラスのメソッドです。繰り返しますが、私はまだ という文字列のforeachを行うことができるときに、これがなぜIEnumerableとして返されるのかわかりません。

通常はインターフェイスで、このようなメソッドを置くとのIEnumerableを返すことができる全ての実施を保証するだろう。 IEnumerablesでは、yieldとcleverロジックを使用して計算を延期することができますが、GetCardNames()を呼び出すと、Arrayは計算を直接実行するため、 IEnumerableを使用する理由はたくさんありますが、しばしば、配列が準拠していることを保証できない何らかの「保証」を指しています。

例3

public IEnumerable<IWebElement> ElementCollection { get; set; } 

これは非常にnoobishいる誰かが、これは が言っているものを私に説明できますか? IEnumerable型のパブリックプロパティですか?プロパティタイプとして インターフェイスを使用すると、他のタイプとどのように違いますか?例: 文字列

これはコードの後半でLINQで使用されていますが、これはまだ私の には含まれていません。この例では、 だけを反復処理したい場合、IEnumerableを使用できますか?

デフォルトのバッカーなどで言ったように、IEnumerableプロパティは公開されています。IEnumerableは繰り返し処理できることを保証しています。あなたがそれを反復することができるのは、アイテムが連続しているか何か他のものであるということを意味するわけではないので、実装は異なる場合があります。これはインターフェイスの強みの1つです。

コード内の別の場所でも、IEnumerableプロパティに異なる型を割り当てることができます。リストを送る人もあれば、配列を送る人もいます。また、計算が必要なときに延期することもできます。

1

その他の回答は非常に徹底的です。

配列、リスト、およびその他のコレクションタイプはすべてIEnumerableを実装しています。メソッドの引数をIEnumerableと宣言すると、メソッドはIEnumerableを実装している限り、実際の型が何であるかを気にしません。

あなたのメソッドがコレクションを通じてfor...eachに行く場合は、なぜそれが配列またはリストである必要があると指定するのですか?より具体的でなくても、具体的にする必要はありません。

これは、メソッドが渡されたパラメータで何をすることを期待しているかを示す方法です。メソッドがIEnumerable<T>というパラメータを受け取った場合、「あなたのコレクションを取り出して列挙します。アイテムを追加または削除しません」という意味です。

パラメータがList<T>またはIList<T>の場合、それを受け取るメソッドはアイテムを追加または削除できます。

説明のためにあまり一般的ではありません。配列をメソッドに渡すと、そのメソッドは配列のソート順を変更する可能性があります。 (正直言って、それは私がいつも心配している可能性はありません)。

これらのタイプを指定すると、それらの動作を絶対に実行することはできませんが、メソッドがその動作を伝達する方法です。あなたはリストに追加します。 IEnumerableを列挙します。

関連する問題