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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With