評価式と型指定 その2
昨日の続き。
これらの条件を満たしている必要があるのだが、ここで大きな問題がある。それは、引数の個数が同一なコンストラクタのオーバロードが複数ある場合、引数が代入可能かを調べるためには、引数がインジェクションされる際の型が必要なのである。これでは堂々巡りだ。さて、どうしたものか。
状況を整理すると、
- コンストラクタインジェクションには引数記述が必要だ(デフォルトコンストラクタは除く)
- インジェクションに適合するコンストラクタ情報を引くには引数の個数と、それぞれの型情報が必要だ
- 式評価によるレイトバインディング無しでインジェクションする場合、型が曖昧になるのでコンストラクタを引けない
ということになる。解決の仕方はいろいろあるが、今回は一番ベタな方法を実装する方法でいくことにした。コンストラクタインジェクションのパラメタの記述においては、以下のような書き方を許可することにしたのである。
1000 2000
見ての通りで、arg要素に新たな属性としてtype属性を追加し、type属性には指定可能な型名(Typeオブジェクトに変換可能な文字列)を指定できるようにする。このように明示的に型指定をされた引数の記述はインジェクション時には、明確に型情報を割り当てられるため、適切なコンストラクタ情報を引くことが可能になる訳だ。
C#の場合、型名の幾つかにおいては"string" "int"等、いわゆる"エイリアス"を略名として記述できるので、エイリアスとしての型名が記述されている場合は、適切な型名に変換する仕組みが新たに必要になる。
エイリアスから正式な型名への変換にはこれまたベタだが、こんな感じでエイリアス用の型名リゾルバを用意してやれば良いだろう。
public class TypeAliasResolver { private static IDictionaryaliases; public const string Int32Alias = "int"; public const string DecimalAlias = "decimal"; public const string CharAlias = "char"; public const string Int64Alias = "long"; public const string Int16Alias = "short"; public const string UInt32Alias = "uint"; public const string UInt64Alias = "ulong"; public const string UInt16Alias = "ushort"; public const string DoubleAlias = "double"; public const string FloatAlias = "float"; public const string BoolAlias = "bool"; public const string StringAlias = "string"; public const string ObjectAlias = "object"; public const string ByteAlias = "byte"; public const string SByteAlias = "sbyte"; static TypeAliasResolver() { aliases = new Dictionary (); aliases[Int32Alias] = typeof(int).FullName; aliases[UInt32Alias] = typeof(uint).FullName; aliases[Int16Alias] = typeof(short).FullName; aliases[UInt16Alias] = typeof(ushort).FullName; aliases[UInt64Alias] = typeof(ulong).FullName; aliases[Int64Alias] = typeof(long).FullName; aliases[DoubleAlias] = typeof(double).FullName; aliases[FloatAlias] = typeof(float).FullName; aliases[BoolAlias] = typeof(bool).FullName; aliases[DecimalAlias] = typeof(decimal).FullName; aliases[CharAlias] = typeof(char).FullName; aliases[StringAlias] = typeof(string).FullName; aliases[ObjectAlias] = typeof(object).FullName; aliases[ByteAlias] = typeof(byte).FullName; aliases[SByteAlias] = typeof(sbyte).FullName; } public static string Resolve(string type) { if (type != null) { if (aliases.ContainsKey(type.ToLower())) { return aliases[type]; } } return type; } private TypeAliasResolver() {} }
ひょっとしたらエイリアスに抜けがあるやもしれない。
11/13 追記