资源管理:use 关键字 (F#)
本主题介绍关键字 use 和 using 函数,它们可以控制资源的初始化和释放。
资源
“资源”这一术语存在多种用法。 没错,资源可以是应用程序使用的数据,如字符串、图形以及类似的内容,但在本文中,资源是指软件或操作系统资源,如图形设备上下文、文件句柄、网络和数据库连接、并发对象(如等待句柄)等。 应用程序在使用这些资源时需要从操作系统或其他资源提供程序获取资源,然后将资源释放到池中,以便将资源提供给另一个应用程序。 若应用程序不将资源释放回公共池,则会出现问题。
管理资源
若要有效而负责地管理应用程序中的资源,您必须及时并且有预见性地释放资源。 .NET Framework 提供了 IDisposable 接口,可帮助您完成此任务。 实现 IDisposable 的类型具有 Dispose 方法,此方法可正确地释放资源。 正确编写的应用程序应确保,在不再需要占用有限资源的任何对象时,立即调用 Dispose。 幸运地是,大多数 .NET 语言都提供了相关支持来简化这一操作,F# 当然也不例外。 有两种支持释放模式的有用语言构造,即 use 绑定和 using 函数。
use 绑定
use 关键字的形式与 let 绑定的形式类似:
use value = expression
它具有与 let 绑定相同的功能,但添加了一个在值超出范围时针对值的 Dispose 调用。 请注意,编译器插入了针对该值的 null 检查,以便在该值为 null 的情况不会尝试调用 Dispose。
下面的示例演示如何使用 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."
提示
可在计算表达式中使用 use,这种情况下将使用 use 表达式的自定义版本。 有关更多信息,请参见序列 (F#)、异步工作流 (F#) 和计算表达式 (F#)。
using 函数
using 函数具有以下形式:
using (expression1) function-or-lambda
在 using 表达式中,expression1 会创建必须释放的对象。 expression1 的结果(必须释放的对象)成为 function-or-lambda 的参数 value。function-or-lambda 可以是一个函数(应采用与 expression1 生成的值匹配的类型的单个剩余参数),或者是一个 lambda 表达式(应采用该类型的一个参数)。 在执行完该函数后,运行时会调用 Dispose 并释放资源(除非该值为 null,此种情况下不要尝试调用 Dispose)。
下面的示例演示包含 lambda 表达式的 using 表达式。
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 jumped over the lazy brown dog."
下一个示例演示包含一个函数的 using 表达式。
let printToFile (file1 : System.IO.StreamWriter) =
file1.WriteLine("Test output");
using (System.IO.File.CreateText("test.txt")) printToFile
请注意,该函数可以是一个已应用某些参数的函数。 下面的代码示例对此进行了演示。 该示例创建一个包含字符串 XYZ 的文件。
let printToFile2 obj (file1 : System.IO.StreamWriter) =
file1.WriteLine(obj.ToString())
using (System.IO.File.CreateText("test.txt")) (printToFile2 "XYZ")
using 函数和 use 绑定完成此任务的方式大致相同。 在调用 Dispose 时,using 关键字可提供更多的控制。 若使用 using,则会在函数或 lambda 表达式的结尾调用 Dispose;若使用 use 关键字,则会在包含代码块的结尾调用 Dispose。 通常,应首选使用 use 而不是 using 函数。