2015年4月15日水曜日

拡張メソッドでイベントを定型化する

.NETでは自作イベントを記述する処理は大体決まっていて、コピペの量産祭になることが多い。
そもそもイベントはメモリリークの原因になることが多いのでRxを使え、との議論もあるがここでは置いておいて。

大体こんな感じのコードが随所に溢れることになる。

//----イベントを宣言
public event HogeEventHandler Hoge;
protected virtual void OnHoge(HogeEventArgs e) {
    if(Hoge != null) {
        Hoge(this,  e);
    }
}

//-----イベントを発生
var e = new HogeEventArgs();
OnHoge(e);

何が嫌かというと、イベントの数だけメソッドが増えてしまうことだ。似たようなコードがずらずらと並んでいるのはとても見栄えが悪い。

そこで半分くらいはネタなのだが、以下のような方法を提案してみる。

public static class EventExtension {
    public static void Fire(this EventArgs e, object sender, dynamic handler) {
        if(handler != null) {
            handler(sender, e);
        }
    }
}

dynamic型を利用しているのが格好悪いが、ハンドラを上手い感じに引数に渡す方法がこれしか見付からなかった。もっと上手い指定の方法があれば良いのだが。

これを定義しておくと、以下のように書くことが出来るようになる。

//----イベントを宣言
public event HogeEventHandler Hoge
//----イベントを発生
var e = new HogeEventArgs();
e.Fire(this, Hoge);

同様にしてCancelEventArgsを拡張してみる。

public static class EventExtension {
    public static void Fire(this CancelEventArgs e, object sender, dynamic before, dynamic after, Action action) {
        if(before != null) {
            before(sender, e);
        }
        if(!e.Cancel) {
            action();
            if(after != null) {
                after(sender, e);
            }
        }
    }
}

これを定義しておくと、 以下のように書くことが出来るようになる。

//----イベントを宣言
public event HogeCancelEventHandler BeforeHoge, AfterHoge;
//----イベントを発生
var e = new HogeCancelEventArgs();
e.Fire(this, BeforeHoge, AfterHoge, ()=> Console.WriteLine("Hogeがキャンセルされなかったので実行したよ!"));

如何だろうか。これで個人的にはかなり楽になったのだが、他にやっている人を見掛けないのでバッドノウハウに分類される技なのかも知れない。

0 件のコメント:

コメントを投稿