资源管理:use 关键字

本主题介绍关键字 useusing 函数,该函数可控制资源的初始化和发布。

资源

“资源”这个词的用法很多。 是的,资源可以是应用程序使用的数据(例如字符串、图形等),但在此处,资源指软件或操作系统资源,例如图形设备上下文、文件句柄、网络和数据库连接、并发对象(如等待句柄等)。 应用程序对这些资源的使用涉及从操作系统或其他资源提供方获取资源,然后将资源发布到池中,以便将其提供给另一个应用程序。 当应用程序不将资源释放回公共池时,会出现问题。

管理资源

若要有效且负责任地管理应用程序中的资源,必须以可预测的方式及时发布资源。 .NET Framework 通过提供 System.IDisposable 接口来帮助你满足此要求。 实现 System.IDisposable 的类型具有 System.IDisposable.Dispose 方法,该方法可正确发布资源。 适当编写的应用程序可保证在不再需要包含受限资源的任何对象时及时调用 System.IDisposable.Dispose。 好在大多数 .NET 语言都支持对该操作的简化,F# 也不例外。 有两个有用的语言构造支持释放模式:use 绑定和 using 函数。

使用绑定

use 关键字具有类似于 let 绑定的形式:

使用 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 将最后一个释放。

注意

你可在计算表达式中使用 use,在这种情况下,要使用自定义版本的 use 表达式。 有关详细信息,请参阅序列异步表达式任务表达式计算表达式

using 函数

using 函数具有以下形式:

using (expression1) function-or-lambda

using 表达式中,expression1 创建必须释放的对象。 expression1 的结果(必须释放的对象)成为函数或 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 jumps 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 时,Dispose 在函数或 lambda 表达式的末尾调用;使用 use 关键字时,Dispose 在包含代码块末尾调用。 一般情况下,应首选使用 use 函数,而不是 using 函数。

另请参阅