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
型を渡すコードはコンパイルエラーにできないか。
というような話は、あとでまた書く。 (追記)書いた。