Как LINQ задерживает выполнение когда в операторе использования

Я должен признать, что я никогда не пробовал это лично.

Однако я вспомнил, что обычный подход к предотвращению состязаний в файловом вводе / выводе состоит в том, чтобы попытаться обработать случай возможной ошибки соответственно.

Следовательно, я посмотрел в QFile::open() , что он предлагает и нашел:

QIODevice::NewOnly : [1111 ]

Ошибка, если открываемый файл уже существует. Создайте и откройте файл, только если он не существует. Существует гарантия от операционной системы, что вы единственный, кто создает и открывает файл. Обратите внимание, что этот режим подразумевает WriteOnly, и его комбинирование с ReadWrite разрешено. Этот флаг в настоящее время влияет только на QFile. Другие классы могут использовать этот флаг в будущем, но до тех пор использование этого флага с любыми классами, кроме QFile, может привести к неопределенному поведению. (начиная с Qt 5.11)

blockquote>

Я только что понял (помимо нашей производительной установки Qt 5.9) у меня есть более новая, которую я установил для приватной игры.

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

#include 

int main()
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  for (int i = 1; i <= 2; ++i) {
    qDebug() << "Iteration" << i;
    QFile qFile("test.txt");
    if (!qFile.open(QIODevice::WriteOnly | QIODevice::NewOnly)) {
      qDebug() << "qFile.open failed! Error code" << qFile.error();
    }
    qFile.write("test");
    qFile.close();
  }
  return 0;
}

Вывод:

Qt Version: 5.11.2
Iteration 1
Iteration 2
qFile.open failed! Error code 5
QIODevice::write (QFile, "test.txt"): device not open

Я все еще не совсем уверен, как выяснить, что это не удалось именно из-за уже существующего файла (а не по любой другой причине). В моем случае точно, но в целом?

(Код ошибки 5 - просто QFileDevice::OpenError .)

12
задан Spence 20 January 2009 в 04:50
поделиться

2 ответа

Я ожидал бы, что только к не работают; 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;
      }
   }
}

Это теперь задерживается, не раздавая контекст данных.

13
ответ дан 2 December 2019 в 07:22
поделиться

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

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 () по существу действует как отложенный с использованием блока .

8
ответ дан 2 December 2019 в 07:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: