ConditionalWeakTableを利用して拡張メソッドに状態を持たせる
拡張メソッドを利用してインタフェースに実装をもたせる場合、インタフェースが公開しているもの以外の状態は利用できない。 が、ConditionalWeakTableを利用することでそれに近いことが実現できる。
class Parameter { public string str { get; set; } } interface IExtensible { } static class Extensions { static ConditionalWeakTable<IExtensible, Parameter> state = new ConditionalWeakTable<IExtensible, Parameter>(); public static void SetStr(this IExtensible target, string str) { state.GetOrCreateValue(target).str = str; } public static string GetStr(this IExtensible target) { return state.GetOrCreateValue(target).str; } }
こんな感じに利用する。
ConditionalWeakTableは連想配列のように働くのだが、Keyへの参照が弱参照で、他の参照がすべてなくなった場合GCにより回収される。
そして、その時ConditionalWeakTable内のレコードも削除されるのだそうだ。至れり尽くせりである。
ちなみに、ConditionalWeakTableのValueは参照型でなくてはいけない。設定のメソッドがないのでさもありなんである。 だが、実際は結構Enum等の値型を入れたいことがある。仕方がないのでこのようなクラスを使っている。
class Box<T>{ public T Value { get; set; } public static implicit operator T(Box<T> target) { return target.Value; } public static implicit operator Box<T>(T target) { return new Box<T> { Value = target }; } }
今ひとつすっきりしないやり方だが、いい方法が見つからなかった。 他の局面でもこのような問題が出ることもあると思うのだが、何かもう少し綺麗なやり方はないのだろうか。