Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quick way to convert a Collection to Array or List?

For every *Collection (HtmlNodeCollection, TreeNodeCollection, CookieCollection etc) class instance that I need to pass to a method which accepts only an array or list (shouldn't have a method that accepts a TreeNodeCollection in the TreeView for example?) I have to write a extension-method like this:

public static TreeNode[] ToArray(this TreeNodeCollection nodes)
        {
            TreeNode[] arr = new TreeNode[nodes.Count];
            nodes.CopyTo(arr, 0);
            return arr;
        }

Or loop over the entire collection adding the items to a output-list and then converting the output-list to an array:

 public static TreeNode[] ToArray(this TreeNodeCollection nodes)
        {
      var output = new List<TreeNode>();
            foreach (TreeNode node in nodes)
                output.Nodes(node);
            return output.ToArray();
 }

So, my question is: I need this extension-methods often. It may allocate a lot of memory if the list are large, as are usually. Why can't I just get a reference (not copy) to the internal array used by this *Collection classes so that I had no need to use that extensions and perfom this memory allocations? or even provide a ToArray() method. We don't need to know its internal implementation or array used in that last case.

like image 700
Jack Avatar asked Apr 12 '15 19:04

Jack


1 Answers

The reason that all BCL collection classes hide their inner array is for reasons of "API niceness". The internal array can change in case it needs to grow or shrink. Then, any user code that has a reference to the old array can become confused. Also, user code might access array indexes that are invalid to access on the collection. If you have a List with Capacity = 16 && Count == 10 and then you can access the internal array at index 15 which the list would not normally allow.

These issues make the API hard to use. They cause support tickets and Stack Overflow questions.

Delete your existing code and replace it with:

TreeNodeCollection nodes;
var myArray = nodes.Cast<TreeNode>().ToArray();

You can make this into an extension method if you feel the need for that. Type the parameter as IEnumerable (no generics). It is a mystery to me why the existing collections in the BCL have not been upgraded to implement IEnumerable<T>. That's why you need the Case. I just created a User Voice item for this.

like image 131
usr Avatar answered Sep 26 '22 01:09

usr