|
|
連載:[完全版]究極のC#プログラミング
Chapter2 ジェネリック
川俣 晶
2009/08/17 |
|
|
2.7 HashtableクラスとDictionaryクラスの非互換性
ジェネリックコレクションは容易に使うことができ、すぐにでも従来のコレクションから移行したいものである。
しかし、中には(従来版からジェネリック版への)機械的な置き換えでは対処できないものもある。特に深刻なのは、HashtableクラスとDictionaryクラスの非互換動作の例だろう。実際にコードを見ていただきたい(リスト2.9参照)。
using System;
using System.Collections;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
try
{
// Hashtableクラス(従来のコレクションクラス)
Hashtable hashtable = new Hashtable();
Console.WriteLine(hashtable[0] == null);
// Dictionaryクラス(ジェネリックコレクション)
Dictionary<int, object> dictionary
= new Dictionary<int, object>();
Console.WriteLine(dictionary[0] == null); // 例外が発生
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
|
|
リスト2.9 HashtableクラスとDictionaryクラスの非互換動作の例 |
True
System.Collections.Generic.KeyNotFoundException: 指定されたキーはディレクトリ内に存在しませんでした。
場所 System.ThrowHelper.ThrowKeyNotFoundException()
場所 System.Collections.Generic.Dictionary`2.get_Item(TKey key)
場所 Program.Main(String[] args) 場所 ……\Program.cs:行 15
|
|
リスト2.9の実行結果 |
このとおり、存在しないキーに対するアクセスは、従来のHashtableクラスではnullを返すが、新しいDictionaryクラスではSystem.Collections.Generic.KeyNotFoundException例外を投げる。
あるキーに対する値が存在するか否かを判定する処理は比較的よくあるが、もし上記のサンプルコードのような方法で判定している場合は書き直す必要がある。あるキーがコレクションに含まれているかは、ContainsKeyメソッドで判定できる。また、キーの存在チェックと値の取得を1回で行う場合は、TryGetValueメソッドという便利なメソッドもある。これを用い、
if (Dictionaryオブジェクト.TryGetValue(キー, out value)) { xxxx }
|
|
といった文を実行すると、キーが存在するときにのみ変数valueに値が入り、if文の条件が成立するので、「xxxx」の部分にvalueの値を使うコードを安全に書くことができる。
しかし、なぜこのような仕様変更が行われたのだろうか? よく考えると新しいDictionaryクラスの仕様は合理的であることがわかる。
たとえば、C# 2.0の追加機能、「null許容型」(第5章参照)を使うと、値としてnullも代入できるint型などを容易に使うことができる。この型の値をコレクションに追加したとき、当然のことながら、nullも有効な値と見なされなければならない。
これを実際に記述した例をリスト2.10に示す(「int?」はnull許容型のint型)。
using System;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
Dictionary<int, int?> dictionary = new Dictionary<int, int?>();
dictionary[0] = null;
Console.WriteLine(dictionary.Count); // 出力:1
Console.WriteLine(dictionary[0] == null); // 出力:True
}
}
|
|
リスト2.10 nullが正規の値となるコレクション |
このプログラムは、コレクションに確かに1つのキーと値のペアを入れている。そのことは、dictionary.Countの値が1であることから確認できる。しかし、格納された値はnullである。
もし、キーが存在しないときに得られる値もnullであれば、nullという値が格納されたのか、キーが存在しないのか、区別ができないことになる。キーがないときは例外を投げるという仕様は、この区別を明確にするために必要とされる対処というわけである。
ただし、例外は重い処理なので、例外を使うよりも上述のContainsKeyメソッドやTryGetValueメソッドで判定するほうがよいだろう。
Insider.NET 記事ランキング
本日
月間