How does LINQ defer execution when in a using statement

后端 未结 2 727
孤城傲影
孤城傲影 2021-02-08 01:36

Imagine I have the following:

private IEnumerable MyFunc(parameter a)
{
   using(MyDataContext dc = new MyDataContext)
   {
      return dc.tablename.Select(row          


        
2条回答
  •  执笔经年
    2021-02-08 02:06

    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 leaving MyFunc), 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 returning IQueryable so that the consumer can "compose" the result (i.e. add OrderBy / Skip / Take / Where etc, and have it impact the final query):

    // this could also be an instance method on the data-context
    internal static IQueryable 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
           }
        }
    }
    

    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.

    private IEnumerable MyFunc(parameter a)
    {
       using(MyDataContext dc = new MyDataContext)
       {
          // or ToList() etc
          return dc.tablename.Where(row => row.parameter == a).ToArray();
       }
    }
    

    If you want to keep it deferred in this case, then you need to use an "iterator block":

    private IEnumerable MyFunc(parameter a)
    {
       using(MyDataContext dc = new MyDataContext)
       {
          foreach(SomeType row in dc
              .tablename.Where(row => row.parameter == a))
          {
            yield return row;
          }
       }
    }
    

    This is now deferred without passing the data-context around.

提交回复
热议问题