質問
いい考えがある yield
いくつかの例を見てきましたが、実際のアプリケーションは思いつきません。特定の問題を解決するためにそれを使用したことがありますか?
(理想的には、他の方法では解決できない問題)
解決
これは古い質問 (ジョン スキート以前?) であることは承知していますが、私は最近この質問を自分自身で検討しています。残念ながら、ここでの現在の回答では(私の意見では)yieldステートメントの最も明白な利点については言及されていません。
yield ステートメントの最大の利点は、標準のリストを使用するよりもはるかに効率的なメモリ使用量で非常に大きなリストを反復処理できることです。
たとえば、100 万行を返すデータベース クエリがあるとします。DataReader を使用してすべての行を取得し、List に格納することができるため、list_size * row_size バイトのメモリが必要になります。
または、yield ステートメントを使用して Iterator を作成し、一度に 1 行だけをメモリに保存することもできます。実際、これにより、大規模なデータセットに対して「ストリーミング」機能を提供できるようになります。
さらに、Iterator を使用するコードでは、単純な foreach ループを使用し、必要に応じてループから抜け出すことを決定できます。早期にブレークした場合、(たとえば) 最初の 5 行だけが必要なときに、データ セット全体の取得を強制していないことになります。
に関して:
Ideally some problem that cannot be solved some other way
yield ステートメントでは、独自のカスタム イテレータ実装を使用して実行できないことは何もできませんが、必要となる複雑なコードを記述する必要がなくなります。複数の方法で解決できない問題は (あるとしても) ほとんどありません。
詳細については、最近の質問と回答をいくつか紹介します。
他のヒント
実際、私は自分のサイトで従来とは異なる方法でそれを使用しています アイデアパイプ
public override IEnumerator<T> GetEnumerator()
{
// goes through the collection and only returns the ones that are visible for the current user
// this is done at this level instead of the display level so that ideas do not bleed through
// on services
foreach (T idea in InternalCollection)
if (idea.IsViewingAuthorized)
yield return idea;
}
したがって、基本的には、アイデアの表示が現在許可されているかどうかを確認し、許可されている場合はアイデアを返します。そうでない場合は、単にスキップされます。これにより、アイデアをキャッシュしながら、承認されたユーザーにアイデアを表示することができます。そうしないと、1 時間ごとにのみ再ランク付けされる場合、権限に基づいて毎回再プルする必要があります。
Enumerable クラスの LINQ 演算子は、yield ステートメントで作成されるイテレータとして実装されます。これにより、ループ内で実際に列挙子を使用するまでは、実際に何も列挙することなく、Select() や Where() などの操作を連鎖させることができます。通常は、 フォーリーチ 声明。また、コレクションの途中で停止することにした場合、IEnumerator.MoveNext() を呼び出すときに計算される値は 1 つだけなので、すべての結果を計算することによるパフォーマンスへの影響を軽減できます。
イテレータを使用して、必要な場合にのみ式が評価される他の種類の遅延評価を実装することもできます。も使用できます 収率 コルーチンのようなもっと派手なものについては。
yield のもう 1 つの有効な用途は、IEnumerable の要素に対して関数を実行し、別の型の結果を返すことです。次に例を示します。
public delegate T SomeDelegate(K obj);
public IEnumerable<T> DoActionOnList(IEnumerable<K> list, SomeDelegate action)
{
foreach (var i in list)
yield return action(i);
}
yield を使用すると、具体的なタイプへのダウンキャストを防ぐことができます。これは、コレクションの利用者がコレクションを操作しないようにするのに便利です。
も使用できます yield return
一連の関数の結果をリストとして扱います。たとえば、従業員に 2 週間ごとに給与を支払う会社について考えてみましょう。次のコードを使用して、給与支払日のサブセットをリストとして取得できます。
void Main()
{
var StartDate = DateTime.Parse("01/01/2013");
var EndDate = DateTime.Parse("06/30/2013");
foreach (var d in GetPayrollDates(StartDate, EndDate)) {
Console.WriteLine(d);
}
}
// Calculate payroll dates in the given range.
// Assumes the first date given is a payroll date.
IEnumerable<DateTime> GetPayrollDates(DateTime startDate, DateTime endDate, int daysInPeriod = 14) {
var thisDate = startDate;
while (thisDate < endDate) {
yield return thisDate;
thisDate = thisDate.AddDays(daysInPeriod);
}
}