在using语句中LINQ如何延迟执行

vu8f3i0k  于 2023-06-19  发布在  其他
关注(0)|答案(2)|浏览(128)

假设我有以下内容:

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()扩展方法,它当然会枚举结果。勾选的答案的行为对于实际回答的问题是完全正确的。
抱歉造成任何混淆。

htzpubme

htzpubme1#

我认为这根本行不通; Select被延迟,因此此时没有数据被消耗。但是,由于您已经释放了data-context(在离开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;
      }
   }
}

这现在被推迟,而不传递数据上下文。

rryofs0p

rryofs0p2#

我刚刚发布了这个问题的另一个延迟执行解决方案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块:

public static IEnumerable<T> Use<T>(this T obj) where T : IDisposable
{
    try
    {
        yield return obj;
    }
    finally
    {
        if (obj != null)
            obj.Dispose();
    }
}

相关问题