PG日誌

受託系 PG が C# の事を書いています

C#のvarとtry~catchはクソじゃなかった

例外をcatch節で受けるときにException型で受けちゃうとコードインスペクションで引っ掛かります。で、ネットでどうなってるのか調べていたときにメッチャパッションしてるエントリを見つけたので思ったこと書こうと思います。

C#のvarとtry~catchが糞すぎる
http://d.hatena.ne.jp/yaneurao/20100929

問題について

以下のコードを記述するとコンパイルが通らないとのこと。

try {
    var hoge = new HogeClass();
    hoge.XXX();
} catch {
    if (hoge!=null)
        hoge.YYY();
}

気持ちは何となく分かります。
確かに、こうしたい時ありますね。

仕様的には、

  • HogeClassはインスタンス生成時に例外が発生する時がある
  • HogeClass#XXX(...)も例外が発生する時がある
  • インスタンス生成に成功してXXX(..)が例外になったらYYY(...)を実行したい

でしょうか。このコード自身の良しあしは別においておき、この部分の一番の問題は、catch節で変数「hoge」が認識されずコンパイルエラーが発生するですね。(1)

それで、そしてその代替案ですが、これもコンパイルエラーになります。

以下に、書き換えるとvarに具体的な型が要求されうっとおしい (2)
具体名を宣言したとしてもnull代入を強要される (3)

var hoge;
try {
    var hoge = new HogeClass();
    hoge.XXX();
} catch {
    if (hoge!=null)
        hoge.YYY();
}

なんというか、せっかく提案したのにコレもダメなの?ってなりますね。なんかMSとc#に自分の事が否定された気持ちになる気がします。

解決策

だけど、この、(1)のcatch節で変数「hoge」が認識されない件はメソッド化すればあっさり解決するのでは?と思います。
「Tryoutパターン」じゃなくて「TryParseパターン」です。

public bool TryCreate(out HogeClass hoge)
{
    try
    {
        hoge = new HogeClass();
        hoge.XXX();
    }
    // 特定の意図した例外だけキャッチするように変更
    catch (HogeClassException ex)
    {
        // 以降生成に失敗の原因がわからないので一応ログに出す
        Debug.WriteLine(ex.ToString());
        if(hoge != null)
        {
            hoge.YYY();
        }
        // この場合、使い物にならないhogeが設定されて戻るが
        // クライアント側での真偽判定を期待する
        return false;
    }
    return true;
}

この後このインスタンスが生成に失敗したらどうしたいかは、戻りのboolを見ればいいんじゃないかなと思います。

もしくは、必ず後処理が必要ならHogeClassにIDisposableをインプリメントしてインスタンス生成した時とXXXと実行した時に確保している資源を解放するようにして

using(var hoge = new HogeClass())
{
    hoge.XXX();
}

ですかね?
この変数をどこかに保持していた場合、不要になった時に

using(this.hoge) { } // 解放するだけでも使える

// if(this.hoge != null)
// {
//     hoge.Dispose();
// }
// に展開される

って書いてもいいですし。

(2)(3)はc#のvarの使用が宣言から推測できる型のシンタックスシュガーなだけなので諦めましょう。
varと言っても強い型の中でのvarなのでスクリプト言語のvarとは同じ名前でも全然違うものですね。
(HogeClassで宣言した変数を後からStreamReaderにはできないのと同じかと思います)

冒頭のコードで、一番意図しているものに近いのは

object hoge = null;
try
{
    hoge = new HogeClass();
    ...

だと思います。

結論

c#のvarとtry~catchはクソじゃなかった!

でした。