Объявить переменную IEnumerable для последующего использования

#c# #.net #linq #c#-4.0

#c# #.net #linq #c #-4.0

Вопрос:

У меня есть запрос LINQ, такой как:

 using(csv.......)
{
    csv.Select(x => new Data() { ID = x[27], Raw = String.Join(",", x) });
}
//Do some stuff

//Now I want to use the result of the query
foreach(var item in ??)
{

}
  

Запрос возвращает IEnumerable в моей using инструкции, но как мне объявить, а затем назначить переменную, чтобы я мог использовать ее позже в foreach инструкции?

Комментарии:

1. Я предполагаю, что запрос больше не работает после удаления MyObject. Это верно?

2. Похоже, в этом и заключается проблема. О, ладонь в ладонь! ОГО! ОГО! ОГО!

Ответ №1:

Вы должны хорошо воспользоваться IEnumerable . Прелесть этого в том, что ваш запрос не оценивается до тех пор, пока вы не понадобитесь. Как только вы выполните ToList() , ваш запрос будет выполнен полностью. Рекомендуется использовать IEnumerable как можно больше.

Вы просто можете определить IEnumerable<Data> во внешней области следующим образом

 IEnumerable<Data> myDataList;
using(myObject.......)
{
    myDataList =csv.Select(x => new Data() { ID = x[27], Raw = String.Join(",", x) });
}
// do your stuffs
// and just use the IEnumerable<Data> in your foreach loop
foreach(var item in myDataList)
{
    // here item is typeof(Data)
}
  

Ответ №2:

Тип запроса — это тот, IEnumerable<Data> который вы можете объявить вне using блока. Однако из комментариев очевидно, что вы не можете перечислять после того, как myObject она была удалена. Если вы не хотите извлекать все элементы в список перед выходом из using блока, ваш единственный вариант — выполнить перечисление внутри using блока. Для извлечения данных из базы данных требуется открытое соединение с этой базой данных и т.д.

 using(myObject.......) 
{ 
  var query = csv.Select(x => new Data() { ID = x[27], Raw = String.Join(",", x) }); 
  //Do some stuff 

  //Now I want to use the result of the query
  foreach (var item in query)
    ...
} 
  

Комментарии:

1. Изначально я пробовал это до того, как спросил, но в переменной ничего не было

2. Я думаю, вам нужно сделать . ToList() для выполнения запроса.

3. @Jon: Когда вы говорите, что в переменной ничего нет, вы имеете в виду, что это null или что это просто пустое значение IEnumerable?

4. @TerryDonaghe: Нет, выполнение foreach приведет к отложенному выполнению запроса и будет иметь преимущество в том, что не будет извлекать все данные в память сразу. Поскольку Джон говорит, что у него в коллекции от шести до восьми миллионов элементов, использование ToList привело бы к значительному и ненужному снижению производительности.

Ответ №3:

Объявить переменную вне блока using.

Вызовите ToList() или ToArray() для выполнения запроса.

 List<Data> data=null;
using(myObject.......)
{
    data=csv.Select(x => new Data() { ID = x[27], Raw = String.Join(",", x) }).ToList();
}
  

Если возможно выполнить запрос после возврата из using предложения, вы могли бы сделать:

 IEnumerable<Data> data=null;
using(myObject.......)
{
    data=csv.Select(x => new Data() { ID = x[27], Raw = String.Join(",", x) });
}
  

Но если это так, почему вы вообще помещаете ее в using предложение?

Если запрос зависит от того, myObject что он не удален, у вас есть два варианта:

  • Используйте ToList() для немедленного выполнения запроса и загрузки всего этого в память.
  • утилизировать myObject позже.

Комментарии:

1. Имеет ли вызов ToList() такое же снижение производительности, как и foreach? Причина, по которой я спрашиваю, заключается в том, что в IEnumerable<T> содержится 6-8 миллионов элементов

2. Список загрузит все элементы в память.

3. Но foreach не будет? У меня не может быть так много памяти!