想象一下,我有以下内容:
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()扩展方法,当然这个方法枚举了结果。勾选答案的行为对于回答的实际问题是完全正确的。
对不起有任何困惑。
答案 0 :(得分:12)
我希望这根本不起作用; Select
被延迟,因此此时没有消耗任何数据。但是,由于您已经处理了数据上下文(在离开MyFunc
之前),因此它永远无法获取数据。更好的选择是将数据上下文传递给方法,以便消费者可以选择生命周期。此外,我建议您返回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();
}
}
如果你想在这种情况下延迟它,那么你需要使用“迭代器块”:
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;
}
}
}
现在推迟了,而没有传递数据上下文。
答案 1 :(得分:8)
我刚刚发布了另一个针对此问题here的延迟执行解决方案,包括以下示例代码:
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
块一样。