usingステートメントの場合、LINQはどのように実行を延期しますか
-
19-08-2019 - |
質問
次のものがあると想像してください:
private IEnumerable MyFunc(parameter a)
{
using(MyDataContext dc = new MyDataContext)
{
return dc.tablename.Select(row => row.parameter == a);
}
}
private void UsingFunc()
{
var result = MyFunc(new a());
foreach(var row in result)
{
//Do something
}
}
ドキュメントによると、linqの実行は、foreachの行で実際に結果を列挙するまで延期されます。ただし、usingステートメントを使用すると、MyFunct()の呼び出しの最後にオブジェクトを確実に確実に収集する必要があります。
実際に何が起こるか、ディスポーザはいつ実行され、結果は実行されますか?
私が考えることができるのは、遅延実行がコンパイル時に計算されることだけです。したがって、実際の呼び出しはコンパイラによってforeachの最初の行に移動され、使用は正しく実行されますが、foreach行まで実行されません? 手伝ってくれる教祖はいますか?
編集:注:このコードは機能しますが、方法がわかりません。
読んでみたところ、コードで、当然結果を列挙するToList()拡張メソッドを呼び出していたことに気付きました。チェックされた回答の動作は、実際に回答された質問に対して完全に正しいです。
ご迷惑をおかけして申し訳ありません。
解決
私はそれが単に機能しないことを期待しています。 Select
は延期されているため、この時点でデータは消費されていません。ただし、データコンテキストを破棄したため(MyFunc
を離れる前に)、データを取得できなくなります。より良いオプションは、データコンテキストをメソッドに 渡すことです。これにより、消費者はライフタイムを選択できます。また、コンシューマが<!> quot; compose <!> quot;できるようにIQueryable<T>
を返すことをお勧めします。結果(つまり、OrderBy
/ Skip
/ Take
/ Where
などを追加し、最終的なクエリに影響を与えます):
// this could also be an instance method on the data-context
internal static IQueryable<SomeType> MyFunc(
this MyDataContext dc, parameter a)
{
return dc.tablename.Where(row => row.parameter == a);
}
private void UsingFunc()
{
using(MyDataContext dc = new MyDataContext()) {
var result = dc.MyFunc(new a());
foreach(var row in result)
{
//Do something
}
}
}
更新:実行を延期したくない場合(つまり、呼び出し側がデータコンテキストを処理したくない場合)、結果を評価する必要があります。これを行うには、結果に対して.ToList()
または.ToArray()
を呼び出して値をバッファリングします。
private IEnumerable<SomeType> MyFunc(parameter a)
{
using(MyDataContext dc = new MyDataContext)
{
// or ToList() etc
return dc.tablename.Where(row => row.parameter == a).ToArray();
}
}
この場合に延期したい場合は、<!> quot; iterator block <!> quot;:
を使用する必要がありますprivate IEnumerable<SomeType> MyFunc(parameter a)
{
using(MyDataContext dc = new MyDataContext)
{
foreach(SomeType row in dc
.tablename.Where(row => row.parameter == a))
{
yield return row;
}
}
}
これは、データコンテキストを渡さずに延期されるようになりました。
他のヒント
この問題に対する別の遅延実行ソリューションを投稿しましたこちら、このサンプルコードを含む:
IQueryable<MyType> MyFunc(string myValue)
{
return from dc in new MyDataContext().Use()
from row in dc.MyTable
where row.MyField == myValue
select row;
}
void UsingFunc()
{
var result = MyFunc("MyValue").OrderBy(row => row.SortOrder);
foreach(var row in result)
{
//Do something
}
}
Use()
拡張メソッドは、基本的に遅延using
ブロックのように機能します。