36

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?

Adam
  • 15,537
  • 2
  • 42
  • 63
Joe W
  • 1,789
  • 3
  • 28
  • 42
  • this has nothing to do with LINQ (the generic collections have existed since .NET 2.0), so I re-tagged it for you. – Adam Nov 06 '12 at 18:11
  • 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. – Servy Nov 06 '12 at 18:20
  • @Servy 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. – Joe W Nov 06 '12 at 18:37

3 Answers3

47

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).

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • I think he wants `object1` to come first in the resulting list, so this won't work. – Lee Nov 06 '12 at 18:15
  • 1
    @Lee Yeah - that's why I tagged that specifically in the question. Also added an option with order being important. – Reed Copsey Nov 06 '12 at 18:16
11

I think the best you can do is:

List<MyObject> newList = new[] { object1 }.Concat(listOfObjects).ToList();
Lee
  • 142,018
  • 20
  • 234
  • 287
  • 2
    +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 ;) – Reed Copsey Nov 06 '12 at 18:20
  • 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. – Servy Nov 06 '12 at 18:21
  • @Servy - The question asked for a more concise method, and this is. – Lee Nov 06 '12 at 18:34
  • 1
    @Servy -- 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. – rory.ap Jun 13 '17 at 16:25
5

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.

Johannes
  • 363
  • 3
  • 15
  • Why not `collection.AddRange(itemsToAdd)` ? – Captain Prinny Jan 06 '21 at 18:36
  • 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](https://learn.microsoft.com/de-de/dotnet/api/system.collections.generic.list-1.addrange) or [ArrayList](https://learn.microsoft.com/de-de/dotnet/api/system.collections.arraylist.addrange)). However, you can create your own extension method to support this. – Johannes Jan 08 '21 at 08:43