Administración de recursos: palabra clave use

En este tema se describen la palabra clave use y la función using, que pueden controlar la inicialización y la liberación de recursos.

Recursos

El término recurso se usa de más de una forma. Sí, los recursos pueden ser datos que usa una aplicación, como cadenas, gráficos y similares, pero en este contexto, recursos se refiere a recursos de software o sistema operativo, como contextos de dispositivos gráficos, identificadores de archivos, conexiones de red y base de datos, objetos de simultaneidad como identificadores de espera, etc. El uso de estos recursos por parte de las aplicaciones implica la adquisición del recurso desde el sistema operativo u otro proveedor de recursos, seguida de la posterior liberación del recurso al grupo para que se pueda proporcionar a otra aplicación. Los problemas se producen cuando las aplicaciones no liberan los recursos al grupo común.

Administrar recursos

Para administrar recursos de forma eficaz y responsable en una aplicación, debe liberar los recursos de forma rápida y predecible. .NET Framework ayuda a hacerlo con la interfaz System.IDisposable. Un tipo que implementa System.IDisposable tiene el método System.IDisposable.Dispose, que libera correctamente los recursos. Las aplicaciones bien escritas garantizan que se llame rápidamente a System.IDisposable.Dispose cuando ya no se necesite algún objeto que contiene un recurso limitado. Afortunadamente, la mayoría de los lenguajes .NET proporcionan compatibilidad para facilitar esta tarea, y F# no es ninguna excepción. Hay dos construcciones de lenguaje útiles que admiten el patrón de eliminación: el enlace use y la función using.

Enlace use

La palabra clave use tiene un formato similar al del enlace let:

use valor = expresión

Proporciona la misma funcionalidad que un enlace let, pero agrega una llamada a Dispose en el valor cuando este se sale del ámbito. Observe que el compilador inserta una comprobación null en el valor, de modo que, si el valor es null, la llamada a Dispose no se intenta.

En el ejemplo siguiente se muestra cómo cerrar un archivo automáticamente mediante la palabra clave 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."

Varias instancias de use se disponen en el orden inverso en el que se declaran. Es decir, la primera use será la última publicada.

Nota:

Puede usar use en expresiones de cálculo, en cuyo caso se emplea una versión personalizada de la expresión use. Para obtener más información, vea Secuencias, Expresiones asincrónicas, Expresiones de tareas y Expresiones de cálculo.

Función using

La función using tiene el siguiente formato:

using (expression1) function-or-lambda

En una expresión using, expression1 crea el objeto que se debe eliminar. El resultado de expression1 (el objeto que se debe eliminar) se convierte en un argumento, value, para function-or-lambda, que es una función que espera un único argumento restante de un tipo que coincida con el valor generado por expression1 o una expresión lambda que espera un argumento de ese tipo. Al final de la ejecución de la función, el runtime llama a Dispose y libera los recursos (a menos que el valor sea null, en cuyo caso no se intenta llamar a Dispose).

En el ejemplo siguiente se muestra la expresión using con una expresión 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."

En el ejemplo siguiente se muestra la expresión using con una función.

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

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

Observe que la función podría ser una función con algunos argumentos ya aplicados. El siguiente ejemplo de código muestra esto. Crea un archivo que contiene la cadena XYZ.

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

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

La función using y el enlace use son formas prácticamente equivalentes de lograr lo mismo. La palabra clave using proporciona más control sobre cuándo se llama a Dispose. Cuando se usa using, se llama a Dispose al final de la función o expresión lambda; cuando se usa la palabra clave use, se llama a Dispose al final del bloque de código contenedor. En general, debe preferir el uso de use en lugar de la función using.

Vea también