C#3.0の拡張メソッドを使って As とか Switch/Case とかを作ってみた

As メソッドの巻

次のようなコードを書く機会が多い。obj が Hoge インスタンスかどうかを判定して、Hoge インスタンスの場合のみ何か特別な処理をしたいのだ。

Hoge hoge = obj as Hoge;
if ( hoge != null ) { ... }

しかし、どうもこのコードが気に入らない。変数 hoge のスコープが気に食わないのだ。hoge は if 文の中でしか使わないのだから、if 分のスコープに閉じ込めてしまいたい。
そこで is 演算子を使って次のように書いてみる。

if ( obj is Hoge ) {
  Hoge hoge = (Hoge)obj;
  ...
}

確かにスコープの問題は解決した。だけどやっぱり気持ち悪い。Hoge インスタンスかどうかの判定が重複しているじゃないか。
というわけで、やっぱり as 演算子に戻して次のように書いてみる。

{
  Hoge hoge = obj as Hoge;
  if ( hoge != null ) { ... }
}

こうすればスコープの問題もOKだし判定も1回だけなのだけれど、さすがに見た目がすっきりしない。うーんうーんと悩んだ末に、次のような拡張メソッドを作ってみた。

public static void As<T>(this object self, Action<T> action)
  where T : class
{
  T arg = self as T;
  if (arg != null) action(arg);
}

コレを使えばこう書ける!

obj.As<Hoge>( hoge => { ... } );

Switch/Case の巻

次のようなコードを書く場面も結構ある。

if ( obj is Foo ) {
  Foo foo = (Foo)obj;
  ...
}
else if ( obj is Bar ) {
  Bar bar = (Bar)obj;
  ...
}
else if ( obj is Buz ) {
  Buz buz = (Buz)obj;
  ...
}

いやー、やっぱりイマイチです、このコード。そこでまず、次の Switch クラスを用意して・・・

class Switch
{
  readonly object _self;
  bool _done = false;

  public Switch(object self) { _self = self; }

  public Switch Case<T>(Action<T> action) where T : class
  {
    if (_done) return this;
    T cast = _self as T;
    if (cast != null) { action(cast); _done = true; }
    return this;
  }
}

次の拡張メソッドを用意すれば・・・

public static Switch Switch( this object self ) { return new Switch( self ); }

こう書ける!

obj.Switch()
  .Case<Foo>( foo => { ... } )
  .Case<Bar>( bar => { ... } )
  .Case<Buz>( buz => { ... } );

とはいえ・・・

object に拡張メソッドを定義するのはちょっと気が引けるなぁ。皆さんどう思います?