Я должен признать, что я никогда не пробовал это лично.
Однако я вспомнил, что обычный подход к предотвращению состязаний в файловом вводе / выводе состоит в том, чтобы попытаться обработать случай возможной ошибки соответственно.
Следовательно, я посмотрел в 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
.)
Я ожидал бы, что только к не работают; 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;
}
}
}
Это теперь задерживается, не раздавая контекст данных.
Я только что опубликовал другое решение этой проблемы с отложенным выполнением здесь , включая этот пример кода:
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 ()
по существу действует как отложенный с использованием блока
.