TextReaderのClose

昨日、数時間悩んだこと。

using System;
using System.IO;
using System.Collections.Generic;
 
class Program
{
  static public void Main(string[] args)
  {
    Console.WriteLine("From string:");
    TestBehavior(FromString("hello"));
    Console.WriteLine("");
    Console.WriteLine("");
 
    Console.WriteLine("Close reader outside method:");
    TextReader reader1 = new StringReader("hello");
    TestBehavior(WithoutClose(reader1));
    reader1.Close();
    Console.WriteLine("");
    Console.WriteLine("");
 
    Console.WriteLine("Close reader inside method:");
    TextReader reader2 = new StringReader("hello");
    TestBehavior(WithClose(reader2));
    Console.WriteLine("");
  }
 
  static void TestBehavior(IEnumerable<string> co)
  {
    Console.WriteLine("1st:");
    foreach (string s in co)
    {
      Console.Write(s + " ");
    }
    Console.WriteLine("");
    Console.WriteLine("2nd:");
    foreach (string s in co)
    {
      Console.Write(s + " ");
    }
  }
 
  static IEnumerable<string> FromString(string source)
  {
    TextReader reader = new StringReader(source);
    int tmp = -1;
    while (-1 != (tmp = reader.Read()))
    {
      char ch = (char)tmp;
      yield return ch.ToString();
    }
    reader.Close();
  }
 
  static IEnumerable<string> WithoutClose(TextReader reader)
  {
    int tmp = -1;
    while (-1 != (tmp = reader.Read()))
    {
      char ch = (char)tmp;
      yield return ch.ToString();
    }
  } 

  static IEnumerable<string> WithClose(TextReader reader)
  {
    int tmp = -1;
    while (-1 != (tmp = reader.Read()))
    {
      char ch = (char)tmp;
      yield return ch.ToString();
    }
    reader.Close();
  }
}

実行すると

From string:
1st:
h e l l o 
2nd:
h e l l o 

Close reader outside method:
1st:
h e l l o 
2nd:


Close reader inside method:
1st:
h e l l o 
2nd:

Unhandled Exception: System.ObjectDisposedException: Cannot read from a closed StringReader
  at System.IO.StringReader.CheckObjectDisposedException () [0x00000] in <filename unknown>:0 
  at System.IO.StringReader.Read () [0x00000] in <filename unknown>:0 
  at Program+<WithClose>c__Iterator1.MoveNext () [0x00000] in <filename unknown>:0 
  at Program.TestBehavior (IEnumerable`1 co) [0x00000] in <filename unknown>:0 
  at Program.Main (System.String[] args) [0x00000] in <filename unknown>:0 

1番目のような挙動を期待していたけど、2番目のように書いててイテレータの挙動に悩んだ。最後は論外。