Последовательности ленивы.Это означает, что последовательность не будет оценена, пока кто-то не попытается получить ее элементы.
Попробуйте:
let s = seq {
for i in 1..1000 do
printfn "%d" i
yield i
}
> Seq.take 3 s
Эта программа печатает только цифры от 1 до 3, даже если определениепоследовательности говорит 1000. Это потому, что вызов Seq.take 3
перечисляет только первые три элемента последовательности, и оценка не продолжается далее.
Теперь давайте перейдем к другому шагу:
let s =
printfn "Creating sequence"
let result = seq { printfn "Returning item"; yield 42 }
printfn "Done creating sequence"
result
При выполнении этого кода выводится «Создание последовательности», затем «Завершено создание последовательности».Но это не печатает «Возвращение товара» вообще.Почему бы и нет?Мы построили последовательность, но никогда не оценили ее.Теперь, если я выполню s
, будет напечатано «Возвращение предмета».
Видите, что происходит?Тело s
завершило выполнение до , и полученная последовательность будет оценена.
То же самое происходит в вашем коде: тело files
завершает выполнение до того, как полученная последовательность будет оценена.И когда тело files
завершает выполнение, reader
удаляется, так как оно было связано с use
.Следовательно, к тому моменту, когда вы получите оценку последовательности, reader
больше не будет действительным, поэтому вы получите ошибку.
Чтобы исправить это, вам нужно убедиться, чтоreader
остается действительным все время, пока выполняется оценка последовательности.Единственный практический способ сделать это - включить все use
в тело последовательности:
let files = seq {
let sql = "exec [sp_name] @StartPeriod"
use conn = new SqlConnection(Shared.connectionString)
use cmd = new SqlCommand(sql, conn)
cmd.Parameters.Add("@StartPeriod", SqlDbType.Date).Value <- StartPeriod
conn.Open()
use reader = cmd.ExecuteReader()
while rdr.Read() do yield DownloadedItem.fromRdr reader
}
Таким образом, вся инициализация происходит каждый раз, когда кто-то пытается перечислить последовательность, и reader
сохраняется в силе до завершения перечисления.