concept
interfaceってなくせないものかな。
C++みたいなconceptというのを考えた。ソースの置き換えみたいな過激なことをせず、かといってinterfaceのように「このメソッドとこのメソッドとこのメソッドが無いとダメ」というのを統一的に設計させるという無理なこともさせない仕組みだ。
まず普通にメソッドを書く。
TResult Using<T,TResult>(T item, Func<T,TResult> func, Action<T> dispose) { try{ return func(item); } finally{ dispose(item); } }
言語機能のusingを模したものだ。こんな風に使う。
var text = Using(new StreamReader(File.OpenRead("hoge.txt")), stream =>{ return stream.ReadToEnd(); }, stream => stream.Dispose());
このstream => stream.Dispose()がめんどくさいので、消せるようにしたい。conceptを使う。
concept<Disposable> TResult Using<Disposable,TResult>(Disposable item, Func<Disposable,TResult> func, Action<Disposable> dispose = disposable => disposable.Dispose()) { ... }
conceptに指定したものはC#4.0の引数の規定値を設定する時に限り好きなメソッド/プロパティを呼び出せる。
これは静的に処理され、呼び出した側にDispose()が存在する場合、
Using(new StreamReader(File.OpenRead("hoge.txt")), stream =>{ return stream.ReadToEnd(); }); ↓ Using(new StreamReader(File.OpenRead("hoge.txt")), stream =>{ return stream.ReadToEnd(); }, disposable => disposable.Dispose());
呼び出し側が置き換えられる。DisposeがなくてCloseしかない場合でも、
static void Dispose(this HogeStream hoge) { hoge.Close(); }
拡張メソッドを使えばconceptに合わせることが出来る。まあこの機能は、
TResult Using<TResult>(HogeStream hoge, Func<HogeStream, TResult> func)
{
return Using(hoge, func, arg => arg.Close());
}
普通に関数作ればいいのだからいらないのかもしれない。しかしDisposableを使うメソッドがたくさんあったら一々書くのはめんどくさい。だからまあ必要だと思う。
だから必然的に、このconceptを導入するには拡張プロパティも導入する必要があるだろう。