Visual Basic 2005 ここが便利!

第5回 Usingステートメントで簡単、確実にファイルをクローズ

株式会社ピーデー 川俣 晶
2005/06/01

Visual Studio 2005や.NET Framework 2.0の登場とともに、プログラミング言語であるVisual Basic .NETも「Visual Basic 2005」へとバージョン・アップする。この新しいVisual Basicには、言語仕様の面でも統合開発環境の面でも、プログラミングを楽にする新機能が満載だ。本連載ではその中でも特に注目すべき便利な機能を1つずつピックアップしながら紹介していく。

usingステートメントの有用性

Back Issue
1
“My”はクラスの海からVBプログラマを救う!?
2 型指定されたコレクションを実現するジェネリック
3 自動生成コードを分離、ソースをすっきりパーシャル・クラス
4 Background Workerで夢のマルチスレッドがついに!

 筆者がC#の採用を決めたとき、C#がJavaよりも圧倒的に優れていると感じた機能がいくつかあった。そのうちの1つが、「usingステートメント」だ。これはまさに「シビレるねぇ」といいたくなるようなゴキゲンな機能である。一度使うと絶対に手放せなくなることは、この私が保証しよう。何しろ、この私自身が、もはや手放せなくなった者の1人であるからだ。

 そして、usingステートメントが有効であることは、C#以外のプログラム言語でも、これに相当する機能を取り込みつつあることが証明していると思う。これから解説するように、Visual Basic 2005でもUsingステートメントが採用され、Visual C++ 2005 (C++/CLI)ではさらに過激になり、usingキーワードすら使わないでそれに相当する機能を利用できるほど深く言語仕様に統合されてしまっている。

Usingステートメントがない場合の問題点

 今回は、Visual Basic 2005でUsingステートメント導入前と、導入後でいかにソース・コードが変わるかを見てみよう。

 ここではテキスト・ファイルを作成するサンプル・プログラムを使うが、特に「何があっても確実にファイルを閉じる」という条件にこだわって取り組んでみよう。

 まずUsingステートメント導入前の状況で書いたサンプル・プログラムだ(Visual Basic 2005 Express Beta 2にてコンソール・アプリケーションとして作成。以降も同じ)。

Module Module1

  Sub Main()
    Dim writer As New System.IO.StreamWriter("c:\sample.txt")
    Try
      writer.WriteLine("(テキスト・ファイルの内容)")
    Finally
      writer.Close()
    End Try
    ' writer.WriteLine("出力できるはずもない無意味な行")
  End Sub

End Module
テキスト・ファイルを作成するサンプル・プログラム(Usingステートメント未使用)
Try-Finallyステートメントを利用して、ファイルが確実に閉じられるようにしている。ちなみにこのサンプル・プログラムは現行のVisual Studio .NET 2003でも実行可能。

 ここで注目すべき点は、Try-Finallyステートメントを使って、ファイルを確実に閉じているところだ。

 もしWriteLineメソッドで例外が発生し、このメソッドを抜け出すとしても、Finallyブロック(FinallyからEnd Tryまでの間)に書かれたCloseメソッドは、よほど特殊なケースを除けば、確実に呼び出される。例外を発生させずに正常に実行を終了した場合もCloseメソッドは確実に呼び出される。つまり、確実にファイルを閉じるという条件を満たすソース・コードとしては、満点を与えてよいコードである。

 しかし、問題点がないわけではない。例えば、Closeメソッドを書く場所を間違えたとしても、コンパイラはエラーや警告を発して教えてくれることはない。そもそも、Try-Finallyステートメントはある処理が確実に実行されることを実現してくれるが、そこで行われる処理が何かは一切関知しない。そのため、プログラマがファイルを閉じるメソッドを書かなければ、確実にファイルを閉じることはできない。

 問題はほかにもある。コメントアウトしている最後の1行を見ていただきたい。この行の「'」記号を取り除いてビルドしてみると、特にエラーも警告も発せられない。しかし、実行すると以下のような例外が発生する。

ハンドルされていない例外: System.ObjectDisposedException: 閉じている TextWriterに書き込むことはできません。
上記サンプル・プログラムでコメント行を有効にしてプログラムを実行した場合に表示されるエラー・メッセージ

 すでにCloseメソッドによりファイルを閉じているわけだから、この結果は当然といえる。しかし、コンパイル時にコンパイラは何も教えてくれない。

Visual Basic 2005のUsingステートメント

 さて、これらの問題を解決するには、Visual Basic 2005で新しく導入されたUsingステートメントを使うことができる。これを使って書き直したソース・コードを以下に示す。

Module Module1

  Sub Main()
    Using writer As New System.IO.StreamWriter("c:\sample.txt")
      writer.WriteLine("(テキスト・ファイルの内容)")
    End Using
    ' writer.WriteLine("コンパイル・エラーになる行")
  End Sub

End Module
Visual Basic 2005のUsingステートメントを利用したテキスト・ファイルの作成

 おどろくなかれ、たったこれだけで、最初のサンプル・プログラムと同等の機能を実現することができる。もちろん、コードが短いことは良いことである。書くのも楽になるし、読むのも楽になる。文句をいうのは、結果ではなくコードの行数で報酬を決められてしまう不幸な境遇のプログラマぐらいだろう。

 さて、ソース・コードを解説しよう。もちろん、「Using」で書き始められた行がUsingステートメントである。

 Using ステートメントでは、通常、何らかのオブジェクトを作成し(New)、その参照を変数に格納する。そして、UsingからEnd Usingまでの範囲を抜け出す際には、その変数が参照しているオブジェクトのDisposeメソッドが確実に呼び出されるという仕組みである(「Dispose」は「処分する」という意味)。

 多くのクラスがDisposeメソッドを実装しているが、StreamWriterクラスの場合、Disposeメソッドはファイルを閉じる機能に相当する(実際、StreamWriterクラスのCloseメソッドはDisposeメソッドを呼び出すだけである)。つまり、正常終了であろうと、例外の発生であろうと、この範囲から抜け出そうとした時点で、確実にファイルは閉じられるのである。

 そして、すでに指摘したいくつかの問題は、すべて解決されている。まず、Closeメソッドを書く場所を間違えた場合、コンパイラが間違いを教えてくれないという問題は、そもそもCloseメソッドを書く必要がないことにより、問題そのものが消滅している。

 また、閉じてしまった後にファイルへアクセスしようとすると、コンパイラが教えてくれることも重要なメリットといえる。例えば、

' writer.WriteLine("コンパイル・エラーになる行")

という行の先頭の「'」記号を外してビルドすると、ビルド・エラーとなってプログラムはコンパイルできない。Usingキーワードで宣言した変数(この場合には変数writer)の有効範囲(スコープ)は、End Usingまでである。そのため、ファイルを閉じた後でこの変数writerにアクセスすることはできないからだ。

リソースとTry-FinallyステートメントとUsingステートメント

 最後にまとめておこう。

 ファイルに何らかのデータを書き込んでいる途中で例外が発生し、ファイルを閉じないまま放置された場合、そのファイルにアクセスできなくなる可能性がある。それ故に、開いたファイルは確実に閉じなくてはならない。これは昔からファイルを扱ううえでの常識である。

 同じように、取得したら確実に解放しなければならない、という強い条件を付けられた機能やリソースはいろいろある。例えばデータベースやネットワークへのコネクションなどはその一例である。

 Try-Finallyステートメントは、このような問題を解決するための切り札といえるだろう。しかし、Try-Finallyステートメントはあまりに原始的すぎて、プログラマへの負担が大きい。つまり、ソース・コードが長くなりがちで、しかも正しく使うには注意力が必要とされる。

 Usingステートメントとは、ファイルを始めとするさまざまなリソースを、もっと短く、もっと安全に、そして、もっと楽に扱えるようにしてくれるゴキゲンな機能なのである。さあ、VBプログラマの皆さんも、このゴキゲンな機能にシビレてみよう。End of Article

 
インデックス・ページヘ  「Visual Basic 2005 ここが便利!」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH