IEnumerableの型を指定したforeach #adcjcs by @masaru_b_cl

この記事はC# Advent Calender 2012 : ATNDへの参加エントリーです。

昨日は@ishisakaさんの「C#でYAMLを使えるか試してみた | OPC Diary – No Code, No Life.」でした。

 

IEnumerable型

古き良きC# 1.0の時代より受け継がれる「Iteratorパターン」のためのインターフェースであるIEnumerable型。.NET 2.0からジェネリック版のIEnumerable<T>型が追加され、昨今では黒歴史扱いを受けたりしています。

しかし、いまだにIEnumberable型のみを実装した型も少なくありません。たとえばSystem.Windows.Forms.Control.ControlsプロパティのControlCollection型などがあります。

そのため、画面のコントロールをすべて舐めるような処理も、型のないIEnumerable型を使う必要があります。

 

foreachによる列挙

IEnumerabe型の列挙といえば、foreachです。for?なにそれ?

ただ、すでに述べたようにIEnumerable型の要素をただ列挙しても、Object型としてしか取得することができません。

// 型推論に任せる
foreach (var item in source)
{
  // itemはObject型になるので、型変換が必要
  var person = item as Person;
  Console.WriteLine("{0}, {1}, {2}", person.Id, person.Name, person.Age);
}

 

これを解決するために、LINQのCast<T>演算子を使うといった方法がありますが、余計な処理が一枚かんでいるという印象はぬぐえません。

// Cast<T>メソッドを通す
foreach (var person in source.Cast<Person>())
{
  Console.WriteLine("{0}, {1}, {2}", person.Id, person.Name, person.Age);
}

 

そこで、おすすめなのが、明示的に型を指定することです。こうすることで、自動的にキャストが行われるため、コードがすっきりします。

// 明示的に型を指定する
foreach (Person person in source)
{
  // personは自動的にPerson型にキャストされる
  Console.WriteLine("{0}, {1}, {2}", person.Id, person.Name, person.Age);
}

 

このことは、C#言語仕様(%ProgramFiles%\Microsoft Visual Studio 11.0\VC#\Specifications\1041\CSharp Language Specification.docx) p.279 「8.8.4 foreachステートメント」の次の内容に対応しています。

ステートメントは次の形式になります。

foreach (V v in x) embedded-statement

 

これは次のように展開されます。

{
  E e = ((C)(x)).GetEnumerator();
  try {
    while (e.MoveNext()) {
      V v = (V)(T)e.Current;
      embedded-statement
    }
  }
  finally {
    … // Dispose e
  }
}

 

サンプル

 

まとめ

C#にはこういった楽をするためのsyntax sugarがたくさんあります。たまに言語仕様をチェックしてみるのも楽しいのではないでしょうか。

次は@Marimoiroさんにバトンタッチです。

C#でゲームつくるです [C# Advent Calender 2012]C#を補助するいろんな脇役

広告

IEnumerableの型を指定したforeach #adcjcs by @masaru_b_cl」への1件のフィードバック

  1. ピンバック: 【メモ】技術系Advent Calender 2012の個人的お気に入り記事(仮) « shobomalog

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中