Вопрос

Представьте, что у меня есть следующее:

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 (), который, конечно, перечисляет результат. Поведение, помеченное галочкой, является совершенно правильным для фактического ответа на вопрос.

Извините за путаницу.

Это было полезно?

Решение

Я ожидаю, что это просто не сработает; Select откладывается, поэтому на данный момент данные не были использованы. Однако, поскольку вы удалили контекст данных (перед тем как покинуть MyFunc), он никогда не сможет получить данные. Лучший вариант - передать контекст данных в метод, чтобы потребитель мог выбрать время жизни. Кроме того, я бы порекомендовал вернуть IQueryable<T>, чтобы потребитель мог & Quot; составить & Quot; результат (например, добавьте 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();
   }
}

Если вы хотите сохранить его в этом случае отложенным, вам нужно использовать " iterator block ":

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;
      }
   }
}

Теперь это отложено без передачи контекста данных.

Другие советы

Я только что опубликовал другое решение этой проблемы с отложенным выполнением здесь , включая этот пример кода:

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 блок.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top