{"id":3441,"date":"2011-10-21T11:03:00","date_gmt":"2011-10-21T11:03:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/some-non-generic-collections\/"},"modified":"2016-07-28T10:50:37","modified_gmt":"2016-07-28T10:50:37","slug":"some-non-generic-collections","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/blogs\/some-non-generic-collections\/","title":{"rendered":"Some non-generic collections"},"content":{"rendered":"<p>Although the collections classes introduced in .NET 2, 3.5 and 4 cover most scenarios, there are still some .NET 1 collections that don&#8217;t have generic counterparts. In this post, I&#8217;ll be examining what they do, why you might use them, and some things you&#8217;ll need to bear in mind when doing so.<\/p>\n<h4>BitArray<\/h4>\n<p><code>System.Collections.BitArray<\/code> is conceptually the same as a <code>List&lt;bool&gt;<\/code>, but whereas List&lt;bool&gt; stores each boolean in a single byte (as that&#8217;s what the backing <code>bool[]<\/code> does), BitArray uses a single bit to store each value, and uses various bitmasks to access each bit individually. This means that BitArray is eight times smaller than a List&lt;bool&gt;. Furthermore, BitArray has some useful functions for bitmasks, like <code>And<\/code>, <code>Xor<\/code> and <code>Not<\/code>, and it&#8217;s not limited to 32 or 64 bits; a BitArray can hold as many bits as you need.<\/p>\n<p>However, it&#8217;s not all roses and kittens. There are some fundamental limitations you have to bear in mind when using BitArray: <\/p>\n<ol>\n<li>\n<p>It&#8217;s a non-generic collection. The enumerator returns <code>object<\/code> (a boxed boolean), rather than an unboxed bool. This means that if you do this:<\/p>\n<pre>foreach (bool b in bitArray) { ... }<\/pre>\n<p><em>Every single<\/em> boolean value will be boxed, then unboxed. And if you do this:<\/p>\n<pre>foreach (var b in bitArray) { ... }<\/pre>\n<p>you&#8217;ll have to manually unbox <code>b<\/code> on every iteration, as it&#8217;ll come out of the enumerator an <code>object<\/code>. Instead, you should manually iterate over the collection using a for loop:<\/p>\n<pre>for (int i=0; i&lt;bitArray.Length; i++) {\n    bool b = bitArray[i];\n    ...\n}<\/pre>\n<\/li>\n<li>Following on from that, if you want to use BitArray in the context of an <code>IEnumerable&lt;bool&gt;<\/code>, <code>ICollection&lt;bool&gt;<\/code> or <code>IList&lt;bool&gt;<\/code>, you&#8217;ll need to write a wrapper class, or use the <code>Enumerable.Cast&lt;bool&gt;<\/code> extension method (although Cast would box and unbox every value you get out of it).<\/li>\n<li>There is no <code>Add<\/code> or <code>Remove<\/code> method. You specify the number of bits you need in the constructor, and that&#8217;s what you get. You can change the length yourself using the Length property setter though.<\/li>\n<li>It doesn&#8217;t implement <code>IList<\/code>. Although not really important if you&#8217;re writing a generic wrapper around it, it is something to bear in mind if you&#8217;re using it with pre-generic code.<\/li>\n<\/ol>\n<p>However, if you use BitArray carefully, it can provide significant gains over a List&lt;bool&gt; for functionality and efficiency of space.<\/p>\n<h4>OrderedDictionary<\/h4>\n<p><code>System.Collections.Specialized.OrderedDictionary<\/code> does exactly what you would expect &#8211; it&#8217;s an IDictionary that maintains items in the order they are added. It does this by storing key\/value pairs in a Hashtable (to get O(1) key lookup) and an ArrayList (to maintain the order). You can access values by key or index, and insert or remove items at a particular index. The enumerator returns items in index order.<\/p>\n<p>However, the <code>Keys<\/code> and <code>Values<\/code> properties return ICollection, not IList, as you might expect; CopyTo doesn&#8217;t maintain the same ordering, as it copies from the backing Hashtable, not ArrayList; and any operations that insert or remove items from the middle of the collection are O(n), just like a normal list.<\/p>\n<p>In short; don&#8217;t use this class. If you need some sort of ordered dictionary, it would be better to write your own generic dictionary combining a <code>Dictionary&lt;TKey, TValue&gt;<\/code> and <code>List&lt;KeyValuePair&lt;TKey, TValue&gt;&gt;<\/code> or <code>List&lt;TKey&gt;<\/code> for your specific situation.<\/p>\n<h4>ListDictionary and HybridDictionary<\/h4>\n<p>To look at why you might want to use <code>ListDictionary<\/code> or <code>HybridDictionary<\/code>, we need to examine the performance of these dictionaries compared to Hashtable and Dictionary&lt;object, object&gt;. For this test, I added n items to each collection, then randomly accessed n\/2 items:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/blogbits\/simon.cooper\/Dictionary%20performance.png\" alt=\"Dictionary%20performance.png\" \/><\/p>\n<p>So, what&#8217;s going on here? Well, ListDictionary is implemented as a linked list of key\/value pairs; all operations on the dictionary require an O(n) search through the list. However, for small n, the constant factor that big-o notation doesn&#8217;t measure is much lower than the hashing overhead of Hashtable or Dictionary.<\/p>\n<p>HybridDictionary combines a Hashtable and ListDictionary; for small n, it uses a backing ListDictionary, but switches to a Hashtable when it gets to 9 items (you can see the point it switches from a ListDictionary to Hashtable in the graph). Apart from that, it&#8217;s got very similar performance to Hashtable.<\/p>\n<p>So why would you want to use either of these? In short, you wouldn&#8217;t. Any gain in performance by using ListDictionary over Dictionary&lt;TKey, TValue&gt; would be offset by the generic dictionary not having to cast or box the items you store, something the graphs above don&#8217;t measure.<\/p>\n<p>Only if the performance of the dictionary is vital, the dictionary will hold less than 30 items, and you don&#8217;t need type safety, would you use ListDictionary over the generic Dictionary. And even then, there&#8217;s probably more useful performance gains you can make elsewhere.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Although the collections classes introduced in .NET 2, 3.5 and 4 cover most scenarios, there are still some .NET 1 collections that don&#8217;t have generic counterparts. In this post, I&#8217;ll be examining what they do, why you might use them, and some things you&#8217;ll need to bear in mind when doing so. BitArray System.Collections.BitArray is&#8230;&hellip;<\/p>\n","protected":false},"author":186659,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[],"coauthors":[],"class_list":["post-3441","post","type-post","status-publish","format-standard","hentry","category-blogs"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/3441","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/186659"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=3441"}],"version-history":[{"count":1,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/3441\/revisions"}],"predecessor-version":[{"id":25404,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/3441\/revisions\/25404"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=3441"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=3441"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=3441"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=3441"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}