LINQ 如何在 using 语句中延迟执行
想象一下我有以下内容:
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 的第一行,导致 using 正确执行,但直到 foreach 行才运行? 有没有大师可以提供帮助?
编辑:注意:这段代码确实有效,我只是不明白如何工作。
我做了一些阅读,我意识到在我的代码中我调用了 ToList() 扩展方法,它当然会枚举结果。 勾选答案的行为对于所回答的实际问题来说是完全正确的。
抱歉造成任何混乱。
Imagine I have the following:
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
}
}
According to the documentation the linq execution will defer till I actual enumerate the result, which occurs in the line at the foreach. However the using statement should force the object to be collected reliably at the end of the call to MyFunct().
What actually happens, when will the disposer run and/or the result run?
Only thing I can think of is the deferred execution is computed at compile time, so the actual call is moved by the compiler to the first line of the foreach, causing the using to perform correctly, but not run until the foreach line?
Is there a guru out there who can help?
EDIT: NOTE: This code does work, I just don't understand how.
I did some reading and I realised in my code that I had called the ToList() extension method which of course enumerates the result. The ticked answer's behaviour is perfectly correct for the actual question answered.
Sorry for any confusion.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我希望这根本行不通;
Select
被延迟,因此此时尚未消耗任何数据。 但是,由于您已经处理了数据上下文(在离开 MyFunc 之前),因此它将永远无法获取数据。 更好的选择是将数据上下文传递到方法中,以便消费者可以选择生命周期。 另外,我建议返回IQueryable
,以便消费者可以“组合”结果(即添加OrderBy
/Skip
/Take
/Where
等,并让它影响最终查询):更新:如果您(评论)不想推迟执行(即您不希望调用者处理与数据上下文),那么您需要评估结果。 您可以通过对结果调用
.ToList()
或.ToArray()
来缓冲值来完成此操作。如果您想在这种情况下保持延迟,那么您需要使用“迭代器块”:
现在可以延迟而不传递数据上下文。
I would expect that to simply not work; the
Select
is deferred, so no data has been consumed at this point. However, since you have disposed the data-context (before leavingMyFunc
), it will never be able to get data. A better option is to pass the data-context into the method, so that the consumer can choose the lifetime. Also, I would recommend returningIQueryable<T>
so that the consumer can "compose" the result (i.e. addOrderBy
/Skip
/Take
/Where
etc, and have it impact the final query):Update: if you (comments) don't want to defer execution (i.e. you don't want the caller dealing with the data-context), then you need to evaluate the results. You can do this by calling
.ToList()
or.ToArray()
on the result to buffer the values.If you want to keep it deferred in this case, then you need to use an "iterator block":
This is now deferred without passing the data-context around.
我刚刚在此问题此处发布了另一个延迟执行解决方案,包括以下示例代码:
Use()
扩展方法本质上就像一个延迟的using
块:I just posted another deferred-execution solution to this problem here, including this sample code:
The
Use()
extension method essentially acts like a deferredusing
block: