tags:

views:

40

answers:

4

I have the following which is an array

package.Resources

If I use

package.Resources.ToList().Add(resouce);

package.Resources doesn't actually contain the new item.

I have to use

var packageList = package.Resources.ToList();
packageList.Add(resource);
package.Resources = packageList.ToArray();

Why is that?

+5  A: 

ToList() creates a completely new, different list based on the original array.

LINQ is read-only; Language INtegrated Query - it is only querying the data, not modifying it. All LINQ methods produce a projection - e.g., they project the original sequence into a new one, so you're always working against that.

Rex M
/slaps his forehead. Duh.
Chad
@Rex M, thanks. So obvious when you put it that way
Chad
@Chad yep, cheers!
Rex M
+1  A: 

The property Resources is returning an IEnumerable. Enumerable.ToList() builds a new list from this IEnumerable. You are then adding an item to a new list, not the original collection that Resources is accessing, hence your update is having no affect.

Paul Ruane
+2  A: 

When you call package.Resources.ToList().Add(resouce);, it's functionally the same as doing this:

var resourcesAsList = new List<WhateverTypeResourcesContains>();
foreach(var item in package.Resources)
{
    resourcesAsList.Add(item);
}
var resourcesAsList.Add(resouce);

What this means is that package.Resources hasn't been modified, you've created a List<T> that contains each item that package.Resources contained.

Rob
+2  A: 

Exanding upon what Rex said, when you call .ToList() on an array object, what you are saying is, "Make me a brand new List object that's a distinct reference from the original array, but use the objects from my original array as the objects in my list."

Because arrays are fixed in size, there's really no way to Add() an item to it without copying the existing array to a new array that has an increased capacity (even ReDim Preserve in the VB world copies the array behind the scense).

Because of this, you should ask yourself why you are using an array if you don't know the total number of items in the array when you instantiate it. When you know the number of items or when you are instantiating the array from an existing List or IEnumerable, arrays can be a decent light-weight way of holding a collection of objects. However, when you don't know the capacity until runtime and the source is not an IEnumerable , a List might be a better option because it is built to grow in capacity as items are added.

I use the following collection types as properties in my classes:

  • IEnumerable
    • I use IEnumerable when I'm going to be iterating over a collection that already exists and I won't be adding to it. For example, if I query a directory for its files and I want to have those files as a property in a class, I might use public IEnumerable<FileInfo> DirectoryFiles {get; set;}.
    • IEnumerable allows me to query over an existing set of data, but I don't necessarily care what collection it is, as long as it implements IEnumerable.
  • List<T>
    • I use a List<T> when I need a collection that could grow or shrink dynamically, i.e. the collection doesn't arealdy exist somewhere else and I may need to add or remove items from it.
    • A good example of this might be if you are allowing a user to add and remove items to a list box in the user interface of your application. Since the items in the list box might grow or shrink, a List<T> makes sense.
  • ObservableCollection<T>
    • I use this type of collection in the Silverlight/WPF world because it has built-in events for when the number of items in the collection changes. This is especially handy for data-binding scenarios when you want a UI element to automatically update when the list changes.

I almost never use Arrays explicitly unless I'm consuming an object that already has arrays. Granted, they're a nice lightweight way in which store a collection, but I can usually get by with the 3 types I listed above.

Ben McCormack
It actually is a List in the class, but the object is returned from a webmethod, which returns it as an array. And I'm adding an item to the object, then passing it to another webmethod to save it. Yes, ideally this wouldn't go through a webservice, but, I have no choice.
Chad
@Chad I know how that goes. I generally end up using lists for lots of the same reasone, i.e. when I'm forced to.
Ben McCormack