views:

193

answers:

4

Hello, I've recently been bitten by the (way too commmon in my opinion) gotcha of Concat returns it's result, rather than appending to the list itself.

For instance.

List<Control> mylist=new List<Control>;
//.... after adding Controls into mylist
MyPanel.Controls.Concat(mylist); //This will not affect MyPanel.Controls at all.

MyPanel.Controls=MyPanel.Controls.Concat(mylist); //This is what is needed, but the Controls reference can not be reassigned (for good reason)

So is there some other way of combining two lists that will work when the collection reference is read-only?

Is the only way to do this with a foreach?

foreach(var item in mylist){
  MyPanel.Controls.Add(item);
}

Is there a better way without the foreach?

A: 

In the off-chance you prefer capitalized ForEach over lowercase foreach:

mylist.ForEach(MyPanel.Controls.Add); 
Jimmy
+4  A: 

Many collections have an AddRange method, winforms ControlCollection is one of them.

MyPanel.Controls.AddRange(mylist.ToArray());

This has the benefit of telling the container you'll be adding many controls at once, so it may delay layout steps until it's done adding all of them.

Ben Voigt
Hmm.. I looked at the arguments and didn't even connect the `ToArray` function with using that...
Earlz
OTOH wrt your question about "combining two lists", List<T>.AddRange accepts IEnumerable<T> so you can pass another List directly in.
Ben Voigt
Adding the ToArray call really doesn't accomplish much except ensure that `mylist` is enumerated twice instead of once.
Joel Mueller
@Joel: ControlCollection.AddRange takes an array, not List, as argument, the ToArray is not optional in the example shown.
Ben Voigt
@Ben - That's unfortunate. I assumed it was like other AddRanges, which take `IEnumerable<T>`
Joel Mueller
A: 

Your question asks about IEnumerable, and the answer to that is always "No" - an IEnumerable is a forward-only "stream" of items.

However, if you can use a more Specialized type - ICollection, IList etc. - then you can use the Add or AddRange methods if available.

Michael Stum
+1  A: 
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> items) {
    foreach(T item in items) collection.Add(item);
}

Then you have:

anyGenericCollection.AddRange(someSequence);

Of course some collections (List<T>, ControlCollection etc) already have an AddRange - this simply makes it available to those that don't.

Marc Gravell
Wouldn't it be better to extend ICollection, not IList, in order to cover types like LinkedList?
Ben Voigt
@Ben - quite possibly ;-p (fixed)
Marc Gravell