この難読化されたコードについて考えてみましょう。その目的は、匿名コンストラクターとそのオブジェクトをyield return
を介してその場で新しいオブジェクトを作成することです。目的は、単にreturn
するだけでローカルコレクションを維持する必要がないようにすることです。
public static List<DesktopComputer> BuildComputerAssets()
{
List<string> idTags = GetComputerIdTags();
foreach (var pcTag in idTags)
{
yield return new DesktopComputer() {AssetTag= pcTag
, Description = "PC " + pcTag
, AcquireDate = DateTime.Now
};
}
}
残念ながら、このコードでは例外が発生します。
エラー28 'System.Collections.Generic.List'はイテレーターインターフェイスタイプではないため、 'Foo.BuildComputerAssets()'の本体をイテレーターブロックにすることはできません
質問
yield return
を適切に使用するにはどうすればよいですか?yield return
ではなくIEnumerable
またはIEnumerator
を返す関数でのみList<T>
を使用できます。
IEnumerable<DesktopComputer>
を返すように関数を変更する必要があります。
または、関数を書き換えて List<T>.ConvertAll
を使用することもできます。
return GetComputerIdTags().ConvertAll(pcTag =>
new DesktopComputer() {
AssetTag = pcTag,
Description = "PC " + pcTag,
AcquireDate = DateTime.Now
});
メソッドの署名が間違っています。そのはず:
public static IEnumerable<DesktopComputer> BuildComputerAssets()
LINQクエリを使用して同じ機能を実装することもできます(C#3.0以降)。これはConvertAll
メソッドを使用するよりも効率的ではありませんが、より一般的です。後で、フィルタリングなどの他のLINQ機能を使用する必要がある場合もあります。
return (from pcTag in GetComputerIdTags()
select new DesktopComputer() {
AssetTag = pcTag,
Description = "PC " + pcTag,
AcquireDate = DateTime.Now
}).ToList();
ToList
メソッドは、結果をIEnumerable<T>
からList<T>
に変換します。個人的にはConvertAll
は好きではありません。LINQと同じことをするからです。ただし、以前に追加されたため、LINQでは使用できません(Select
と呼ばれているはずです)。