Gerenciamento de recursos: a palavra-chave use

Este tópico descreve a palavra-chave use e a função using, que podem controlar a inicialização e a liberação de recursos.

Recursos

O termo recurso é usado de mais de uma maneira. Sim, os recursos podem ser dados que um aplicativo usa, como cadeias de caracteres, gráficos e similares, mas nesse contexto, recursos se referem a recursos de software ou sistema operacional, como contextos de dispositivo gráfico, identificadores de arquivos, conexões de rede e banco de dados, objetos de simultaneidade, como identificadores de espera e assim por diante. O uso desses recursos por aplicativos envolve a aquisição do recurso do sistema operacional ou de outro provedor de recursos, seguido pela versão posterior do recurso para o pool para que ele possa ser fornecido a outro aplicativo. Problemas ocorrem quando os aplicativos não liberam recursos de volta para o pool comum.

Gerenciando recursos

Para gerenciar recursos com eficiência e responsabilidade em um aplicativo, você deve liberar recursos prontamente e de maneira previsível. O .NET Framework ajuda você a fazer isso fornecendo a interface System.IDisposable. Um tipo que implementa System.IDisposable tem o método System.IDisposable.Dispose, que libera corretamente recursos. Aplicativos bem escritos garantem que System.IDisposable.Dispose é chamado prontamente quando qualquer objeto que contém um recurso limitado não é mais necessário. Felizmente, a maioria das linguagens .NET oferece suporte para facilitar isso, e F# não é exceção. Há dois constructos de linguagem úteis que dão suporte ao padrão de descarte: a associação use e a função using.

usar Associação

A palavra-chave use tem um formulário semelhante à da associação let:

usar valor = expressão

Ele fornece a mesma funcionalidade que uma associação let, mas adiciona uma chamada a Dispose no valor quando o valor sai do escopo. Observe que o compilador insere uma verificação nula no valor, de modo que, se o valor for null, a chamada para Dispose não será tentada.

O exemplo a seguir mostra como fechar um arquivo automaticamente usando a palavra-chave use.

open System.IO

let writetofile filename obj =
   use file1 = File.CreateText(filename)
   file1.WriteLine("{0}", obj.ToString() )
   // file1.Dispose() is called implicitly here.

writetofile "abc.txt" "Humpty Dumpty sat on a wall."

Várias instâncias de use são descartadas na ordem inversa na qual são declaradas. Ou seja, o primeiro use será o último lançado.

Observação

Você pode usar use em expressões de computação, nesse caso, uma versão personalizada da expressão use é usada. Para obter mais informações, consulte Sequências, Expressões assíncronas, Expressões de tarefa e Expressões de computação.

usando Função

A função using tem a seguinte forma:

using (expression1) function-or-lambda

Em uma expressão using, expression1 cria o objeto que deve ser descartado. O resultado de expression1 (o objeto que deve ser descartado) torna-se um argumento, value, para function-or-lambda, que é uma função que espera um único argumento restante de um tipo que corresponde ao valor produzido por expression1 ou uma expressão lambda que espera um argumento desse tipo. No final da execução da função, o runtime chama Dispose e libera os recursos (a menos que o valor seja null, nesse caso, a chamada para Descarte não é tentada).

O exemplo a seguir demonstra a expressão using com uma expressão lambda.

open System.IO

let writetofile2 filename obj =
    using (System.IO.File.CreateText(filename)) ( fun file1 ->
        file1.WriteLine("{0}", obj.ToString() )
    )

writetofile2 "abc2.txt" "The quick sly fox jumps over the lazy brown dog."

O exemplo a seguir mostra a expressão using com uma função.

let printToFile (file1 : System.IO.StreamWriter) =
    file1.WriteLine("Test output");

using (System.IO.File.CreateText("test.txt")) printToFile

Observe que a função pode ser uma função que já tem alguns argumentos aplicados. O código de exemplo a seguir demonstra isso. Ele cria um arquivo que contém a cadeia de caracteres XYZ.

let printToFile2 obj (file1 : System.IO.StreamWriter) =
    file1.WriteLine(obj.ToString())

using (System.IO.File.CreateText("test.txt")) (printToFile2 "XYZ")

A função using e a associação use são maneiras quase equivalentes de realizar a mesma coisa. A palavra-chave using fornece mais controle sobre quando Dispose é chamado. Quando você usa using, Dispose é chamado no final da função ou expressão lambda; quando você usa a palavra-chave use, Dispose é chamado no final do bloco de código de conteúdo. Em geral, você deve preferir usar use em vez da função using.

Confira também