maxfie1d のブログ

マイクロソフト系技術ネタを中心に書きます。

C# の珍しいキーワード、using

C# を使っていて、滅多にお目にかからないキーワードが存在します。

前回の checked/unchecked、implicit/explicit, unsafe キーワードに引き続き、 今回は using キーワードのお話です。

maxfie1d.hatenablog.com maxfie1d.hatenablog.com maxfie1d.hatenablog.com

using には 2通りの使い方がある

usingキーワードには2つの使い方があります。

  1. using ディレクティブ (using System; みたいなの)
  2. using ステートメント (using (var resource = ...) { ... } みたいなの)

  3. の方は初心者でも馴染みがあると思いますが、 初めて 2. を見た時はusingってこういう使われ方もするの!?と驚くと思います。

というわけで 2. の方のusingを説明したいと思います。

using ステートメントの意義

C#GCがあるので不要になったものは自動的に後始末されますが、 ファイルやストリームなど使い終わったら即座に破棄するのが望ましいものもあります。

そういう即座に破棄するべきリソースはC#では共通してIDisposableインターフェースを実装するのが作法になっています。 IDisposableDisposeメソッドだけを持つインターフェースで、このDisposeメソッドを呼び出しさえすればリソースが 解放されるようにプログラムします。

namespace System
{
    //
    // Summary:
    //     Provides a mechanism for releasing unmanaged resources.
    //     マネージドでないリソースを解放する仕組みを提供します
    public interface IDisposable
    {
        //
        // Summary:
        //     Performs application-defined tasks associated with freeing, releasing, or resetting
        //     unmanaged resources.
        //     マネージドでないリソースを解放したりリセットすることに関する
        //     アプリケーション定義のタスクを行います
        void Dispose();
    }
}

IDisposableインターフェースを実装しているということは、逆に言えば 「使い終わったら必ず破棄してね」ということですが、破棄のし忘れというのはよくあることです。 また破棄のし忘れをIDEが警告を出してくれたらいいんですがそういうわけでもありません(おそらくチェックしてくれるツールはあります)。 また本来Disposeメソッドが呼ばれるようにしていたとしても途中で例外が発生して実は呼び出されなかったみたいなことも起こり得ります。 これの対策としてtry-catch-finallyで真面目に囲むとそれはそれで読みにくくもなります。

そこでusingステートメントの出番です。

using ステートメントの使い方

using (var resource = ...) { ごにょごにょする } が基本形です。 生成するインスタンスはもちろんIDisposableを実装していなければなりません。 ごにょごにょした後は自動的にリソースが解放されます。例外が発生しても解放されます。 usingさえ使えば安全にリソースの解放が行われます。

namespace ConsoleApp2
{
    class Disposable : IDisposable
    {
        public void Dispose() => throw new NotImplementedException();
    }

    class Program
    {
        static void Main(string[] args)
        {
            using (var d = new Disposable())
            {
                // ごにょごにょする
            }
        }
    }
}

ちょっと応用的な使い方

using ステートメント なので下のコードは正常なコードです。

if (cond)
    using (var d = new Disposable())
    {
        ...
    }

using (var d1 = new Disposable())
using (var d2 = new Disposable())
{
    ...
}