As you know generics were only introduced to the .NET Framework in version 2.0. Originally we had a lot of collections in the System.Collections namespace that can store objects. In version 2.0 we added the System.Collections.Generic namespace to support generic collections that can store any specific type.
If you have legacy code or even if you kept using the old non-generic collections for other reasons you may want to consider converting your code to use the generic collections instead. Here are a few reasons why:
OK, so now I convinced you that you should go back and revise your existing code (not to mention any new code you’re writing) to use generic collection but how exactly should you go about it?
Luckily, most of the non-generic collections (with the exception of BitArray) have very good generic counterparts. The following table illustrates what type to replace for what:
Notice that in most of these cases you would have to figure out what the T is in the generic class. This assumes you used to store just one type of elements in your collection. If you are storing more than one type you should find the common base-class. In the worse case you can use Object but that would lose most of the benefits of generics.
Let’s look at an example:
This is the old code using non-generic Stack:
using System;
using System.Collections;
Stack MRUFiles = new Stack();
MRUFiles.Push("first");
MRUFiles.Push("second");
MRUFiles.Push("third");
Console.WriteLine(MRUFiles.Pop() as string);
Console.WriteLine(MRUFiles.Peek() as string);
Console.WriteLine(MRUFiles.Count.ToString());
Same code would look like this using generic Stack<String>:
using System.Collections.Generic;
Stack<string> MRUFiles = new Stack<string>();
Console.WriteLine(MRUFiles.Pop());
Console.WriteLine(MRUFiles.Peek());
BEFORE
IDictionaryEnumerator de = m_Datastore.GetEnumerator();
while (de.MoveNext()) {
ilcc.Datastore[(String)de.Key] = de.Value;
}
AFTER
IEnumerator<KeyValuePair<String, Object>> de = m_Datastore.GetEnumerator();
ilcc.Datastore[de.Current.Key] = de.Current.Value;
If you want the quick “golden hammer” workaround to the thread safety issues, you can just lock on the SyncRoot of the Dictionary (after casting to ICollection), but this is most likely unnecessarily expensive for your app. But first we’ll first show the golden hammer technique. Note that wrapping every calls to Dictionary this way will perform the equivalent of Hashtable’s #7b behavior but is stronger than Hashtable’s #7a.
String myKey = "key";
String myValue = "value";
Hashtable myHashtable = new Hashtable();
Hashtable mySynchronizedHashtable = Hashtable.Synchronized(myHashtable);
myHashtable.Add(myKey, myValue);
Dictionary<String, String> myDictionary = new Dictionary<String, String>();
lock (((ICollection)myDictionary).SyncRoot) {
myDictionary.Add(myKey, myValue);
The decision to remove the synchronized wrapped from generics was based on the observation that you often want to perform synchronization at a higher level in your application, and that our synchronized wrappers led to a false sense of security (and flawed code). This puts developers in the position of thinking more heavily about synchronization, but we decided this was the right call. This decision is discussed more thoroughly here: http://blogs.msdn.com/bclteam/archive/2005/03/15/396399.aspx.
As mentioned above, the golden hammer workaround (used with all calls to Dictionary, including reads) is stronger than #7a. If you lock before every call, then you can have at most one reader or writer at a time. However, the Hashtable.Item property is single reader/multiple writer threadsafe. If you want this same behavior, you can use a ReaderWriterLock or, if you have Orcas installed, ReaderWriterLockSlim.
In general, the best decision for the #7 conversion will depend on the needs of your app: do you want multiple reader/single writer thread safety? Do you want to lock on the Dictionary SyncRoot or a different object, to coordinate accesses among the Dictionary and another collection (discussed in above-mentioned blog)? You can use our suggestions as starting points and customize depending on the needs of your app.
"Whereas the non-generic collections offered a synchronized wrappers through their APIs — e.g. Hashtable.Synchronized—the non-generics don’t."
Shouldn't it be generics instead of non-generics in the end of the sentence above?
Hi,
I couldn't agree more about the reasons to switch to generic collections. However, it seems like you have forgotten to convert the collections in System.Collections.Specialized. I for one like to use HybridDictionary since it will give me OK performance for both small and large collections and I would love a generic alternative to use. Do you plan to create a System.Collections.Generic.Specialized or System.Collections.Specialized.Generic?
Take care,
Finnsson
>Additional Considerations ...
>3. Hashtable.Add() returns the index
No, that seems wrong. Probably a "copy'n'paste" bug from "4. ArrayList.Add()", isn't it?
Although, that would be one nice feature to have ...
Reminds me of ListDictionary and it's friends in System.Collections.Specialized.
Any hints on how to migrate those?
Any news on Set<T>?
i think there is no need for a Specialized generic namespace as all of the non-generic classes have their generic equivalent implementations. For the HybridDictionaty it seems straightforward to use a SortedList/SortedDictionary with an initial capacity depending on scenario.
Trackback from http://dotmad.blogspot.com/2007/06/non-generic-to-generic-types-conversion.html
If you're using a VB.NET project then be careful - ordinary collections are indexed from 1 whereas System.Collections.Generic.List is indexed from 0.
Those of you who are already using Silverlight 1.1 Alpha may have seen that the familiar non-generic
Henry,
You are correct and the blog was fixed.
Also, for the Specialized Collections there are no direct non-generic equivilants and so I ommited them from this post.
As for Set<T>, we have HashSet<T> introduced in Orcas see http://blogs.msdn.com/bclteam/archive/2006/11/09/introducing-hashset-t-kim-hamilton.aspx for details.
What about other kinds of set types? There does not seem to be an ISet<T> interface or even an abstract Set<T> to extend.
The paragraph before the last one has the below sentence as
"However, the Hashtable.Item property is single reader/multiple writer threadsafe."
Shouldn't the above sentence be rephrase as
"However, the Hashtable.Item property is multiple reader/single writer threadsafe."
Silverlight 1.1の基本クラス ライブラリにおける非ジェネリック系のCollectionについて Alpha版で調査をなされていらっしゃるお客さまも多いのではと思いますが、Silverlightのランタイムにおいて非ジェネリック系のコレクション
Alpha版で調査をなされていらっしゃるお客さまも多いのではと思いますが、Silverlightのランタイムにおいて非ジェネリック系のコレクション クラスを取り除く予定でございます。また、ジェネリックのコレクション
We have just been bitten by the fact that Dictionary is not multiple reader/single writer thread-safe.
We had simply replaced all usages of Hashtable with Dictionary, and we were not aware that Dictionary is not thread-safe at all. According to MSDN, it is not even safe for multiple readers (no writers)!
For now, we have decided to go back to Hashtable as we can not accept the loss of performance we will face if we need to use locks for all read access. The ReaderWriterLock is not an option as it is notoriously slow.
I guess we will use ReaderWriterLockSlim when Orcas ships.
Does anyone know a good Hashtable<T> implementation for .Net 2.0? It need to have the same threading characteristics as Hashtable.
I really think it is a huge mistake that such a class is not included with the framework. It is something that is needed all the time by high perf. web and client/server applications.
Bind a Collection to a GridView