連載:[完全版]究極のC#プログラミング

Chapter3 新しい繰り返しのスタイル ― yield return文とForEachメソッド

川俣 晶
2009/08/31

3.9 catchできない制約

 yield return文に慣れると、リスト3.8のようなコードを書いてみるプログラマーも出てくると思う。

using System;
using System.Collections.Generic;
using System.IO;

class Program
{
  private static IEnumerable<string> readTextFile(string filename)
  {
    StreamReader reader = File.OpenText(filename);
    try
    {
      for (; ; )
      {
        string s = reader.ReadLine();
        if (s == null) break;
        yield return s;
      }
    }
    catch (IOException e)
    {
      Console.WriteLine(e.ToString());
    }
    finally
    {
      reader.Close();
    }
  }

  static void Main(string[] args)
  {
    foreach (string s in readTextFile(@"c:\test.txt"))
    {
      Console.WriteLine(s);
    }
  }
}
リスト3.8 コンパイルできない例

 だが、このコードはコンパイルできない。

 catch 句を含む try ブロックの本体で値を生成することはできません。

 というエラーが出てしまうからだ。

 実は、yield return文は、例外処理のためのtry〜catch構文の中で使用できないという制約を持つ。制約があるのはこの組み合わせだけである。たとえば、yield break文をtry〜catch構文の中で使用することはできるし、yield return文は、try〜finally構文の中で使用することができる。

 そこで、yield return文のみ、try〜catch構文から外すように書き直したのがリスト3.9である。

using System;
using System.Collections.Generic;
using System.IO;

class Program
{
  private static IEnumerable<string> readTextFile(string filename)
  {
    StreamReader reader = File.OpenText(filename);
    try
    {
      for (; ; )
      {
        string s;
        try
        {
          s = reader.ReadLine();
        }
        catch (IOException e)
        {
          Console.WriteLine(e.ToString());
          yield break;
        }
        if (s == null) break;
        yield return s;
      }
    }
    finally
    {
      reader.Close();
    }
  }

  static void Main(string[] args)
  {
    // 実行時にはテキストファイル「c:\test.txt」が必要
    foreach (string s in readTextFile(@"c:\test.txt"))
    {
      Console.WriteLine(s);
    }
  }
}
リスト3.9 リスト3.8をコンパイル可能に修正した例

 見てのとおり、かなり回りくどくなったが、同じ意図を記述することはできる。


 INDEX
  [完全版]究極のC#プログラミング
  Chapter3 新しい繰り返しのスタイル ― yield return文とForEachメソッド
    1.3.1 「繰り返し」という古くて新しい問題
    2.3.2 数を数えるというサンプル
    3.3.3 C# 1.xによるRangeクラスの実装
    4.3.4 C# 3.0によるRangeクラスの実装
    5.3.5 yield break文による中断
    6.3.6 yieldは予約語ではない
    7.3.7 1つのクラスに複数の列挙機能を付ける
    8.3.8 自動的に作られるオブジェクトと二重利用
  9.3.9 catchできない制約
    10.3.10 制約の真相―見た目と違う真実の姿
    11.3.11 ForEachメソッドを使う別解
    12.3.12 性能比較
 
インデックス・ページヘ  「[完全版]究極のC#プログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間