System.Web.HttpSessionStateが典型例だが、グローバルな辞書オブジェクトがIDictionary<string, object>型だったりする。そうすると、こんなのをよく見る。
public static class FooKeys
{
public const string Key1 = "FooKeys.Key1";
public const string Key2 = "FooKeys.Key2";
...
}
public static class BarKeys
{
public const string Key1 = "BarKeys.Key1";
public const string Key2 = "BarKeys.Key2";
...
}こんな感じで、Foo関係のキーとBar関係のキーがバッティングしないように、キー文字列に規約を持ち込んだりして。 でもこれって型安全じゃないよね。
辞書がグローバルだからつらいのかもしれない。Foo関係の辞書とBar関係の辞書が別インスタンスになってれば、キーがバッティングする危険性は下げられるだろう。
public readonly Dictionary<string, object> FooDictionary = new Dictionary<string, object>();
public readonly Dictionary<string, object> BarDictionary = new Dictionary<string, object>();でもこれも型安全じゃないよね。
Foo関係のキーとBar関係のキーが別の型なら、もうすこしましかもしれない。 いっそ列挙型ならどうだろう。
public enum FooKeys
{
Key1, Key2, //...
}
public enum BarKeys
{
Key1, Key2, //...
}
public readonly Dictionary<FooKeys, object> FooDictionary = new Dictionary<FooKeys, object>();
public readonly Dictionary<BarKeys, object> BarDictionary = new Dictionary<BarKeys, object>();ところで、TValueがobject型なのも型安全ではない。
たとえばstring型を格納する場合とint型を格納する場合があったらどうするのがいいか。
public enum FooStringKeys
{
Key1, Key2, //...
}
public enum FooIntKeys
{
Key1, Key2, //...
}
public readonly Dictionary<FooStringKeys, string> FooStringDictionary = new Dictionary<FooStringKeys, string>();
public readonly Dictionary<FooIntKeys, int> FooIntDictionary = new Dictionary<FooIntKeys, int>();まあこうやって並べるのが簡単ではある。 でも、もっと工夫はできないのか。
たとえば、var dict = DictionaryGroup<FooKeys>みたいな型のオブジェクトがあって、
dict.Add<int>(FooKeys.IntKeys.Key1, 123); とか、string value = dict.Get<string>(FooKeys.StringKeys.Key2);とかできないか。(イメージはジェネリックなインデクサなんだけど、C#では実現できないので、Add<T>()やGet<T>()で代用している)
その場合、dict.Add<int>()やdict.Get<int>()にFooKeys.StringKeys型を渡すコードはコンパイルエラーにできないか。
そしてもちろん、dictに対してBarKeys.IntKeys型やBarKeys.StringKeys型を渡すコードはコンパイルエラーにできないか。
というような話は、あとでまた書く。 (追記)書いた。