代码之家  ›  专栏  ›  技术社区  ›  Spence

在using语句中,Linq如何延迟执行

  •  11
  • Spence  · 技术社区  · 16 年前

    假设我有以下几点:

    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()扩展方法,当然它枚举了结果。勾选答案的行为与实际回答的问题完全正确。

    不好意思弄混了。

    2 回复  |  直到 16 年前
        1
  •  12
  •   Marc Gravell    16 年前

    我希望这根本不起作用; 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;
          }
       }
    }
    

    现在,这在不传递数据上下文的情况下被延迟。

        2
  •  8
  •   dahlbyk    15 年前

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