MaSiMan
MaSiMan

Reputation: 690

Initialize get-only collection in object initializer from existing collection

I have a class with a get-only collection property. I would like to initialize the collection with the values from an existing collection.

I know that it is possible to initialize the collection using a collection initializer. I could also create the object and then use AddRange on the collection to add the items of the existing collection. This would however create the object with an empty list and add the existing items afterwards.

Is there a way to create the object with the List properly initialized in the first place (without adding a constructor, of course)?

using System.Collections.Generic;

namespace EmptyConsoleApp
{
    internal class Program
    {
        public static void Main(string[] args)
        {
            // Compiles, but is not what I need
            var firstHolder = new Holder()
            {
                TheList = {"A", "B"}
            };

            // Compiles, but initializes the list after object creation
            var existingList = new List<string>() {"Foo", "Bar"};
            var secondHolder = new Holder();
            secondHolder.TheList.AddRange(existingList);

            // Does not compile
            var thirdHolder = new Holder()
            {
                TheList = {existingList}
            };
        }
    }

    internal class Holder
    {
        public Holder()
        {
            TheList = new List<string>();
        }

        public List<string> TheList { get; }
    }
}

Upvotes: 6

Views: 1608

Answers (3)

Jend DimShu
Jend DimShu

Reputation: 97

it is not possible to initialize a read only property from outside of the class itself.

collection initializer is just a simplified syntax version and it does not mean using this syntax you have the same access as if you are in the class constructor

 thirdHolder.TheList = existingList; // this is the traditional way

Perhaps you can use factory class pattern like this

   internal class Program
{
    public static void Main(string[] args)
    {
        // Compiles, but is not what I need
        var firstHolder = new Holder()
        {
            TheList = { "A", "B" }
        };

        // Compiles, but initializes the list after object creation
        var existingList = new List<string>() { "Foo", "Bar" };
        var secondHolder = new Holder();
        secondHolder.TheList.AddRange(existingList);

        // Does not compile
        //var thirdHolder = new Holder()
        //{
        //    TheList =  existingList 
        //};

        //thirdHolder.TheList = existingList; // this is the traditional way
        var thirdHolder = Holder.HolderFactory(existingList);
    }
}


internal class Holder
{
    public Holder()
    {
        TheList = new List<string>();
    }

    public static Holder HolderFactory(List<string> theList)
    {
        return new Holder(theList);
    }
    private Holder(List<string> theList)
    {
        this.TheList = theList;
    }
    public List<string> TheList { get; }
}

Upvotes: 0

nvoigt
nvoigt

Reputation: 77304

Is there a way to create the object with the List properly initialized in the first place (without adding a constructor, of course)?

No

It's not. That's what a constructor does. If you don't want to do it in the constructor, there is no way to do it.

Upvotes: 0

Patrick Hofman
Patrick Hofman

Reputation: 156988

No. You can't assign this read-only property from a collection initializer. It is read-only after all.

TheList = { "A", "B" } works since it calls Add on TheList (once for each item added), it doesn't create and assign a new instance, which it is not allowed to.

TheList = { existingList } doesn't work since there is a typing issue (TheList = { existingList[0] } does work).

The best option you have it to create a constructor parameter and drop your idea of using collection initializers for something it isn't fit for.

Upvotes: 3

Related Questions