Menu
Coddy logo textTech

IDisposable と using ステートメント

CoddyのC#ジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 45/70。

一部のオブジェクトは、ガベージコレクターが自動的にクリーンアップできないリソース(ファイルハンドル、データベース接続、ネットワークソケットなど)を保持します。IDisposable インターフェースは、これらのリソースを使い終わったときに解放するための標準的な方法を提供します。

クラスは、Dispose() メソッドを提供することで IDisposable を実装します。

public class FileHandler : IDisposable
{
    private bool disposed = false;
    
    public void Dispose()
    {
        if (!disposed)
        {
            Console.WriteLine("Releasing resources...");
            disposed = true;
        }
    }
}

Dispose() を手動で呼び出すこともできますが、その行に到達する前に例外が発生した場合はどうなるでしょうか?using ステートメントは、問題が発生した場合でもクリーンアップが行われることを保証します:

using (FileHandler handler = new FileHandler())
{
    // ハンドラーを使用して作業を行う
}  // ここで Dispose() が自動的に呼び出される

モダンな C# では、using 宣言によってよりクリーンな構文が提供されており、オブジェクトがスコープ外に出たときに自動的に破棄されます。

void ProcessFile()
{
    using FileHandler handler = new FileHandler();
    // handler を操作する
}  // メソッドの終了時に Dispose() が呼び出される

using ステートメントは、IDisposable を実装する任意の型で使用できます。StreamReaderSqlConnection、および HttpClient などの組み込みクラスはすべてこのインターフェースを実装しており、適切なリソース管理を簡単かつ確実に行うことができます。

challenge icon

チャレンジ

簡単

IDisposable インターフェースと using ステートメントを使用した適切なリソース管理を実演する、データベース接続シミュレーターを構築しましょう。接続がいつ開かれ、いつ閉じられたかを追跡し、リソースが常に適切に解放されることを保証するクラスを作成します。

コードは2つのファイルに分けて構成します:

  • DatabaseConnection.cs: DataAccess 名前空間内に、IDisposable を実装する DatabaseConnection クラスを作成します。この接続クラスは以下の要件を満たす必要があります:
    • コンストラクタを通じて設定される ConnectionName プロパティ(string、読み取り専用)を持つこと
    • プライベートな boolean フィールドを使用して、接続が破棄(dispose)されたかどうかを追跡すること
    • オブジェクトが作成されたとき(コンストラクタ内)に Connection opened: {ConnectionName} と出力すること
    • Dispose() メソッドを実装し、Connection closed: {ConnectionName} と出力すること。ただし、まだ破棄されていない場合に限ります(二重破棄を防止するため)
    • Executing on {ConnectionName}: {sql} を返す Query(string sql) メソッドを持つこと
  • Program.cs: メインファイルで、データベース接続に対して using ステートメントを使用し、適切なリソース管理を実演します。接続を作成し、クエリを実行し、using ブロックにクリーンアップを自動的に処理させます。

2つの入力を受け取ります:

  • 接続名(例:MainDB
  • 実行するSQLクエリ(例:SELECT * FROM Users

using ステートメントを使用して接続を作成してください。ブロック内で Query メソッドを呼び出し、その結果を出力します。using ブロックが終了すると、Dispose() が自動的に呼び出されます。

例えば、入力が MainDBSELECT * FROM Users の場合、出力は以下のようになります:

Connection opened: MainDB
Executing on MainDB: SELECT * FROM Users
Connection closed: MainDB

using ブロックが終了したときに接続が自動的に閉じられることに注目してください。手動で Dispose() を呼び出すことを覚えておく必要はありません。このパターンにより、ブロック内で例外が発生した場合でも、リソースが常にクリーンアップされることが保証されます!

チートシート

IDisposable インターフェースは、ガベージコレクターが自動的にクリーンアップできないリソース(ファイルハンドル、データベース接続、ネットワークソケットなど)を解放するための標準的な方法を提供します。

クラスは、Dispose() メソッドを提供することで IDisposable を実装します:

public class FileHandler : IDisposable
{
    private bool disposed = false;
    
    public void Dispose()
    {
        if (!disposed)
        {
            Console.WriteLine("Releasing resources...");
            disposed = true;
        }
    }
}

using ステートメントは、例外が発生した場合でも、クリーンアップが自動的に行われることを保証します:

using (FileHandler handler = new FileHandler())
{
    // ハンドラーを操作する
}  // ここで Dispose() が自動的に呼び出されます

モダンな C# では、using 宣言を使用したよりクリーンな構文が提供されています:

void ProcessFile()
{
    using FileHandler handler = new FileHandler();
    // ハンドラーを操作する
}  // メソッドの終了時に Dispose() が呼び出されます

using ステートメントは、StreamReaderSqlConnectionHttpClient などの組み込みクラスを含む、IDisposable を実装する任意の型で使用できます。

自分で試してみよう

using System;
using DataAccess;

class Program
{
    public static void Main(string[] args)
    {
        string connectionName = Console.ReadLine();
        string sqlQuery = Console.ReadLine();
        
        // TODO: 'using' ステートメントを使用して DatabaseConnection を作成します
        // using ブロック内:
        // 1. sqlQuery を使用して Query メソッドを呼び出します
        // 2. Query メソッドの結果を表示します
        // using ブロックが終了すると、Dispose メソッドが自動的に呼び出されます
        
    }
}
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

オブジェクト指向プログラミングのすべてのレッスン