C#3.0でMix-in(みたいなの)ができる件
ある型Aからある型Bへの変換をする処理を書く時にはよくTypeConverter型を継承して型コンバータを書いている。
型コンバータの利点は、.NET標準の機構であるというのもあるけど、変換元の型にカスタム属性で型コンバータを関連付ければ、
↓こんな風に
TypeConverter tc = TypeDescriptor.GetConverter(typeof(型));
TypeDescriptorを使っていつでも*1型コンバータにアクセスできること。変換の処理を変換元の型から切り離せるということも、プログラムの見通しをよくするのに役立つ。
そういう理由で型コンバータをよく書くわけだけど、毎回毎回TypeDescriptorを使って型コンバータを取り出して変換するのは案外めんどくさい。だからその処理をラップしたメソッドを変換元の型に
↓こんな風に
[TypeConverter(typeof(HogeConverter))] class Hoge { /// <summary> /// 現在のオブジェクトを指定した型に変換します。 /// </summary> /// <param name="toType">変換先の型</param> /// <returns>変換後のオブジェクト</returns> public Hoge2 ConvertTo(Type toType) { TypeConverter tc = TypeDescriptor.GetConverter(this.GetType()); return tc.CanConvertTo(typeof(toType)) ? tc.ConvertTo(this, toType) : null; } }
実装するわけだけど、こんなメソッドをクラス毎に作るのもまためんどくさい。
こういう場合はこのメソッドを持つ抽象クラスを作るか、ユーティリティクラスを作るかになるけど、前者はオブジェクト指向の定石から考えれば最もやってはいけないパターン*2だし、後者は求めているもの*3とは違う。
でもC#3.0の拡張メソッドだったら簡単に解決できる事に気がついた。
まずは以下のインターフェースを定義する。
public interface IConvertable { }
このインターフェースはただの目印。
で、このインターフェースに対する拡張メソッドを提供するクラス
static class ConvertableExtension { public static T ConvertTo<T>(this IConvertable obj) { TypeConverter tc = TypeDescriptor.GetConverter(obj.GetType()); return tc.CanConvertTo(typeof(T)) ? (T)tc.ConvertTo(obj, typeof(T)) : default(T); } }
TypeConverterを取り出して、変換処理を行うだけ。
これがあれば、以下のようにIConvertableを実装するだけで、変換用のメソッドが呼び出せる。
[TypeConverter(typeof(HogeConverter))] class Hoge : IConvertable { } class Program { static void Main(string[] args) { Hoge obj = new Hoge(); obj.ConvertTo<int>(); obj.ConvertTo<string>(); } }
使いすぎると危険といわれる拡張メソッドもこんな風に使えば、IConvertableを継承したように見えるので混乱を避けられると思う。