下図の中にあるコードは「yield ステートメントは、匿名メソッドまたはラムダ式の内部では使用できません」というコンパイルエラーが出ます。
では、Result型のイテレータを返す関数オブジェクト(Func<IEnumerable<Result>>)は作れないのでしょうか?
いえ、あります。
上の図のスタティックコンストラクタの2行目※の部分です。
※テキストの改行ではなくセミコロン基準です。
iterateFunc = new Func<IEnumerable<int>>(Iterate);
ラムダ式では式(構文)として記述できないだけで、宣言箇所と呼び出し方法の組み合わせによって動作が変わることはありません。
これはデリゲートや匿名メソッドで行った場合も当てはまります。
説明すればするほど、「あぁ、そんなことか。試してみるまでもないじゃん。」と思う人が増えるので、解説が不親切ですがこの辺でやめておきます。
(この記事の最後に貼ってある「この記事に関係する過去の記事」もご覧ください。)
動作するサンプルコードと実行中の様子を以下に示します。
using System;
using System.Collections.Generic;
using System.Threading;
namespace IteratorInFunc
{
static class Program
{
// 逐次処理をする関数オブジェクト
private static Func<IEnumerable<int>> iterateFunc;
// 1 メソッドによる実装
private static IEnumerable<int> Iterate()
{
for (int i = 0; i < 10; ++i)
{
Thread.Sleep(1000);
yield return i;
}
}
// スタティックコンストラクタ
static Program()
{
// 2 【コンパイルエラー】ラムダ式バージョン
//iterateFunc =
// () =>
// {
// for (int i = 0; i < 10; ++i)
// {
// Thread.Sleep(1000);
// yield return i;
// }
// };
iterateFunc = new Func<IEnumerable<int>>(Iterate);
}
// メインメソッド
static void Main(string[] args)
{
foreach (var result in iterateFunc())
{
DateTime dt = DateTime.Now;
System.Diagnostics.Debug.WriteLine(String.Format("{0} {1}", result, (dt.Second * 1000 + dt.Millisecond).ToString("D5")));
}
}
}
}
(Posted Date) 19:20