리소스 관리: use 키워드(F#)
이 항목에서는 리소스 초기화와 리소스 해제를 제어하는 데 사용할 수 있는 use 키워드와 using 함수를 설명합니다.
리소스
리소스라는 용어는 여러 가지 의미를 갖습니다. 리소스는 문자열, 그래픽 등과 같이 응용 프로그램에 사용되는 데이터일 수도 있지만 여기서 말하는 리소스란 그래픽 장치 컨텍스트, 파일 핸들, 네트워크 및 데이터베이스 연결, 대기 핸들 같은 동시성 개체 등의 소프트웨어 또는 운영 체제 리소스를 가리킵니다. 응용 프로그램에 이러한 리소스를 사용하기 위해서는 운영 체제나 기타 리소스 공급자로부터 리소스를 획득해야 합니다. 그런 다음 이렇게 확보했던 리소스를 다른 응용 프로그램에서도 사용할 수 있도록 리소스 풀에 해제하는 작업이 뒤따라야 합니다. 문제는 응용 프로그램에서 리소스를 공용 풀에 다시 해제하지 않는 경우에 발생합니다.
리소스 관리
응용 프로그램에서 리소스를 책임지고 효율적으로 관리하기 위해서는 리소스를 예측 가능한 방식으로 즉시 해제해야 합니다. .NET Framework에서는 리소스를 해제하는 데 도움을 주기 위해 IDisposable 인터페이스를 제공합니다. IDisposable을 구현하는 형식에는 리소스의 올바른 해제를 담당하는 Dispose 메서드가 있습니다. 응용 프로그램을 제대로 작성했으면 한정된 리소스를 보유하고 있는 개체가 더 이상 필요하지 않게 되는 즉시 Dispose가 호출됩니다. 다행히 대부분의 .NET 언어에서는 이러한 호출을 더 쉽게 처리하는 지원 기능을 제공하며 F#의 경우도 마찬가지입니다. Dispose 패턴을 지원하는 언어 구문으로는 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가 됩니다. 삭제해야 할 개체를 인수로 받는 이 함수는 expression1을 통해 생성된 값에 일치하는 형식의 나머지 인수 하나를 필요로 하는 함수이거나 해당 형식의 인수를 필요로 하는 람다 식입니다. 함수 실행 마지막에 Dispose가 런타임 호출되고 리소스가 해제됩니다. 단, 값이 null이면 Dispose가 호출되지 않습니다.
다음 예제에서는 람다 식이 포함된 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 바인딩은 거의 같은 방식으로 동일한 작업을 수행합니다. 그러나 using 키워드를 사용하면 Dispose의 호출 시점을 더 구체적으로 제어할 수 있습니다. using을 사용하는 경우 Dispose는 함수나 람다 식의 마지막에 호출되는 반면, use 키워드를 사용하는 경우 Dispose는 바깥쪽 코드 블록의 마지막에 호출됩니다. 일반적으로 using 함수 대신 use를 사용하는 것이 더 좋습니다.