Initialize list with both a single object and another list of objects
Asked Answered
S

3

39

I want to initialize a list with an object and a list of objects in that specific order. Currently, I am doing:

List<MyObject> list = new List<MyObject>();
list.Add(object1); // object1 is type MyObject
list.AddRange(listOfObjects); // listOfObjects is type List<MyObject>

I was hoping to consolidate that into an initialization statement (the syntax is wrong of course):

List<MyObject> newList = new List<MyObject>() { object1, listOfObjects };

Is there a way to do this concisely?

Sculpt answered 6/11, 2012 at 18:8 Comment(3)
this has nothing to do with LINQ (the generic collections have existed since .NET 2.0), so I re-tagged it for you.Liederman
What problem do you have with your first code snippet? How is it in any way unsatisfactory or problematic. Virtually any other option will be more complex, take more code, be less readable, and very likely be less performant. I'm sure there are more problematic aspects of your project you could spend time fixing.Infiltrate
@Infiltrate I didn't state that my code fragment was problematic. I asked if there was a more concise way of initializing the list. I don't know all of the options that are out there, hence why I asked the question. I agree that most other ways (the few that I know) are more complex or less readable. Thanks for your input.Sculpt
G
53

If the order of the elements is not important, you can use:

List<MyObject> newList = new List<MyObject>(listOfObjects) { object1 };

This works by using the List<T> constructor which accepts an IEnumerable<T>, then the collection initializer to add the other items. For example, the following:

static void Main()
{
    int test = 2;
    List<int> test2 = new List<int>() { 3, 4, 5 };
    List<int> test3 = new List<int>(test2) { test };

    foreach (var t in test3) Console.WriteLine(t);

    Console.ReadKey();
}

Will print:

3
4
5
2

Note that the order is different than your original, however, as the individual item is added last.

If the order is important, however, I would personally just build the list, placing in your first object in the initializer, and calling AddRange:

List<MyObject> newList = new List<MyObject> { object1 };
newList.AddRange(listOfObjects);

This makes the intention very clear, and avoids construction of temporary items (which would be required using LINQ's Concat, etc).

Gio answered 6/11, 2012 at 18:14 Comment(2)
I think he wants object1 to come first in the resulting list, so this won't work.Adah
@Adah Yeah - that's why I tagged that specifically in the question. Also added an option with order being important.Gio
A
12

I think the best you can do is:

List<MyObject> newList = new[] { object1 }.Concat(listOfObjects).ToList();
Adah answered 6/11, 2012 at 18:12 Comment(4)
+1 from me - but realize this does create some extra "garbage" since you're making an array that just gets thrown away. Not a big deal, but seems like a bit of a mess to avoid a method call ;)Gio
Do you think that this is more readable or in any way easier to understand than the code snippet he started with? I say that this is a step backwards, not forwards.Infiltrate
@Infiltrate - The question asked for a more concise method, and this is.Adah
@Infiltrate -- I found use for this when calling a base class constructor, where it's not straightforward to use multiple statements to create a combined collection.Santosantonica
P
7

This can be achieved with the help of extension methods, e.g.

public static class CollectionExtensions
{
    public static void Add<T>(this ICollection<T> collection, IEnumerable<T> itemsToAdd)
    {
        foreach (var item in itemsToAdd)
        {
            collection.Add(item);
        }
    }
}

Usage is exactly as it was suggested in the question:

var newList = new List<MyObject>
   {
      object1,
      listOfObjects
   };

Some explanation can be found in the C# Programming Guide about Object and Collection Initializers (I could not find better words):

Collection initializers let you specify one or more element initializers when you initialize a collection type that implements IEnumerable and has Add with the appropriate signature as an instance method or an extension method.

Plasterboard answered 12/8, 2020 at 10:27 Comment(2)
Why not collection.AddRange(itemsToAdd) ?Airlia
Because there exists no (extension) method AddRange for ICollection (the type used for the extension method). Only specific collection types support AddRange (such as List<T> or ArrayList). However, you can create your own extension method to support this.Plasterboard

© 2022 - 2024 — McMap. All rights reserved.