Управление ресурсами с помощью use и using

Последнее обновление: 05.01.2024

Нередко приложение использует различные системные ресурсы - сетевые подключения, файлы, подключения к базам данных и т.д., которые необходимо освобождать после завершения работы с ними. Фреймвокр .NET помогает эффективно освобождать ресурсы, предоставляя интерфейс System.IDisposable. Тип, который реализуют интерфейс System.IDisposable, имеет метод Dispose(), который позволяет должным образом освободить ресурсы. И язык F# предоставляют две полезные языковые конструкции, которые позволяют автоматически вызывать метод Dispose: привязка use и конструкция using.

привязка use

Привязка use имеет следующую форму:

use значение = выражение

После use указывается имя значения, и далее ему присваивается значение некоторого выражения. Привязка use напоминает стандартную привязку let за тем исключением, что для значения автоматически вызывается метод Dispose(), когда это значение покинет область видимости.

Стоит отметить, что также автоматически производится проверка на null: если значение равно null, то метод Dispose() не вызывается (так как нечего освобождать).

Пример применения:

let writeData (filename: string) (data: string) =
    use writer: System.IO.StreamWriter = new System.IO.StreamWriter(filename)
    writer.WriteLine(data)
    // writer.Dispose() вызывается автоматически в конце функции

writeData "hillo.txt" "Hello Worlds"

printfn "Запись завершена"

Здесь функция writeData выполняет запись строки в определенный файл. Для записи с помощью привязки use определяется значение writer, которое представляет встроенный тип System.IO.StreamWriter. Этот тип представляет поток для записи в файл. В конструктор этого типа передается имя файла.

Для записи строки у объекта StreamWriter вызывается метод WriteLine(), в который передается записываемая строка.

Поскольку с объектом System.IO.StreamWriter связывается дескриптор файла, в который идет запись, то после окончания записи надо закрыть файловый поток и тем самым освободить связанный файл. В общем случае для этого применяется метод Close(), который неявно вызывает метод Dispose(). Однако поскольку мы применяем привязку use, нам явным образом не надо ничего закрывать. Когда закончится область видимости значения writer, а это произойдет при завершении функции, для объекта writer автоматически будет вызван метод Dispose, и связанный файл будет закрыт.

Если в одной области видимости определеяется несколько значений с помощью use, то они освобождаются в порядке, прототивоположном объявлению.

Функция using

Другую форму освобождения ресурсов предоставляет функция using. Она имеет следующий синтаксис:

using (выражение) функция/лямбда

После слова using в скобках указывается выражение, которое создает объект, использующий некоторый системный ресурс. Этот объект передается в качестве параметра в функцию или лямбда-выражения, который указываются в конце конструкции using. После завершения работы фукции using созданный объект автоматически закрывается. Например, перепишем предыдущий пример с помощью функции using:

let writeData (filename: string) (data: string) =

    using (new System.IO.StreamWriter(filename)) ( fun writer ->
        writer.WriteLine(data)
    ) // writer.Dispose() вызывается автоматически в конце функции

writeData "hillo.txt" "Hello Work"

printfn "Запись завершена"

Здесь выражение после using опять же создает объект System.IO.StreamWriter для записи в файл. Этот объект передается через параметр writer в последующее лямбда-выражение.

Вместо лямбда-выражения можно использовать функции:

let writeLine (writer: System.IO.StreamWriter) = writer.WriteLine("Hello Word")

let writeData (filename: string) =
    using (new System.IO.StreamWriter(filename)) writeLine

writeData "hillo.txt" 

printfn "Запись завершена"

Здесь функция using автоматически вызывает функцию writeLine, передавая в нее объект StreamWriter.

Если вызываемая функция должна принимать еще какие-то параметры, то они указываются перед параметром, который представляет освобождаемый ресурс:

let writeLine (data:string) (writer: System.IO.StreamWriter) = writer.WriteLine(data)

let writeData (filename: string) (data: string) =
    using (new System.IO.StreamWriter(filename)) (writeLine data)

writeData "hillo.txt" "Hello Word"

printfn "Запись завершена"

Обратите внимание, что в этом случае не надо явным образом передавать объект StreamWriter в функцию writeLine, он по прежнему передается автоматически.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850