How to initialize a List<T> to a given size (as opposed to capacity)?
Asked Answered
T

18

180

.NET offers a generic list container whose performance is almost identical (see Performance of Arrays vs. Lists question). However they are quite different in initialization.

Arrays are very easy to initialize with a default value, and by definition they already have certain size:

string[] Ar = new string[10];

Which allows one to safely assign random items, say:

Ar[5]="hello";

with list things are more tricky. I can see two ways of doing the same initialization, neither of which is what you would call elegant:

List<string> L = new List<string>(10);
for (int i=0;i<10;i++) L.Add(null);

or

string[] Ar = new string[10];
List<string> L = new List<string>(Ar);

What would be a cleaner way?

EDIT: The answers so far refer to capacity, which is something else than pre-populating a list. For example, on a list just created with a capacity of 10, one cannot do L[2]="somevalue"

EDIT 2: People wonder why I want to use lists this way, as it is not the way they are intended to be used. I can see two reasons:

  1. One could quite convincingly argue that lists are the "next generation" arrays, adding flexibility with almost no penalty. Therefore one should use them by default. I'm pointing out they might not be as easy to initialize.

  2. What I'm currently writing is a base class offering default functionality as part of a bigger framework. In the default functionality I offer, the size of the List is known in advanced and therefore I could have used an array. However, I want to offer any base class the chance to dynamically extend it and therefore I opt for a list.

Tessie answered 21/1, 2009 at 20:54 Comment(14)
"EDIT: The answers so far refer to capacity, which is some else than pre-populating a list. For example, on a list just created with a capacity 10, one can not do L[2]="somevalue"" Given this modification, perhaps you should reword the Question Title...Compassion
But, what's the use of pre-populating a list with empty values, cause that's what the topicstarter is trying to do ?Venter
Frederik: Exactly. When would this be necessary...ever?Idzik
If positional mapping is that crucial, wouldn't it make more sense to use a Dictionary<int, string>?Georgia
@Boaz: I don't think you understand the concepts at work here.Wig
I've ended up doing using List like this instead of Dictionary<int, string> for quick and dirty projects in Unity because Lists work out of the box with Unity inspector.Langford
Almost no penalty is not no penalty. .NET has both List and Array for a reason.Foch
List is not a replacement for Array. They solve distinctly separate problems. If you want a fixed size, you want an Array. If you use a List, you are Doing It Wrong.Bitch
"One could quite convincingly argue that lists are the "next generation" arrays, adding flexibility with almost no penalty" - well one is wrong :) can you create a multi-dimensional list? the equivalent to string[] s=new string[5,5,5,5,5] (and not =new string[][][][][]) - nope.. a List is a List.. if you want the next generation of arrays you will need to develop it.Negotiant
However, does List avoid the single object size limit or Array? This would be a case to use a fixed length List (then use Parallelism to populate it).Suffumigate
I always find answers that tries to hammer in arguments like "I can't see why I would ever need ..." aggravating. It only means just that: you couldn't see it. It doesn't necessarily mean anything else. I respect that people want to suggest better approaches to a problem, but it should be phrased more humbly, e.g. "Are you sure you need a list? Perhaps if you told us more about your problem...". This way it becomes pleasant, engaging, and encourages the OP to improve their question. Be a winner - be humble.Steric
My use-case for needing this is working within the constraints of collections in MVC. The fields are output using either an index or what looks like a GUID in the HTML field name/ID: <input name="Property[0].Property1" /> or `<input name="Property[ecee9ab3-cc42-423b-95d8-f61ae237832e].Property1" />. I'm tasked with dynamically adding new inputs for additional items as they are added, and since indexes are being used on the form currently and I don't know whether I can mix indexes and GUID's I'm opting for KISS and just outputting additional indexes. For this, I need the list large enough.Obscuration
… The arguments on this question is weird. People saying "this goes against why lists are created" really have no imagination. Case in point, I need a list of default values upon initialization, and then some outside factor adds on to the list immediately after.Derisive
I slapped the OP's Add loop into a creational helper method, and ... I'm moving on! 😅Legist
C
106

I can't say I need this very often - could you give more details as to why you want this? I'd probably put it as a static method in a helper class:

public static class Lists
{
    public static List<T> RepeatedDefault<T>(int count)
    {
        return Repeated(default(T), count);
    }

    public static List<T> Repeated<T>(T value, int count)
    {
        List<T> ret = new List<T>(count);
        ret.AddRange(Enumerable.Repeat(value, count));
        return ret;
    }
}

You could use Enumerable.Repeat(default(T), count).ToList() but that would be inefficient due to buffer resizing.

Note that if T is a reference type, it will store count copies of the reference passed for the value parameter - so they will all refer to the same object. That may or may not be what you want, depending on your use case.

EDIT: As noted in comments, you could make Repeated use a loop to populate the list if you wanted to. That would be slightly faster too. Personally I find the code using Repeat more descriptive, and suspect that in the real world the performance difference would be irrelevant, but your mileage may vary.

Codify answered 21/1, 2009 at 21:0 Comment(15)
I realize this is an old post, but I am curious. Enumerable.Repeat fares much worse compared to a for loop, as per the last portion of the link (dotnetperls.com/initialize-array). Also AddRange() has O(n) complexity as per msdn. Isn't it a bit counter productive to use the given solution instead of a simple loop?Classicism
@Jimmy: Both approaches will be O(n), and I find this approach to be more descriptive of what I'm trying to achieve. If you prefer a loop, feel free to use it.Codify
@Jimmy: Also note that the benchmark there is using Enumerable.Repeat(...).ToArray(), which is not how I'm using it.Codify
@JonSkeet, I see that now. I did run some tests now, and for int lists the for loop runs slightly faster, but for decimal list your solution with repeat works slightly faster.Classicism
Don't really see the need for two separate overloads. Just declare it as public static List<T> Repeated(int count, TSource value = default(T)) instead.Steric
@AnorZaken: Well it's not really an overload given that it's a separate method name - and bear in mind that this answer was written in January 2009, before C# even had optional parameters...Codify
@JonSkeet technically correct as always. :P Well anyway I quite often try to add (what I hope is) useful comments to old answers for newcomers to find. It's not personal criticism. It's just that when googling comes up with old answers, it doesn't hurt to add a modern perspective. And the point is visibility - so for a small change a comment makes more sense than a new answer in my opinion. Because frankly, there's nothing inherently wrong with your answer. It's just a bit dated, as you said. Cheers! :)Steric
I've used the Enumerable.Repeat() in the following way (implemented Pair just like the C++ equivalent): Enumerable.Repeat( new Pair<int,int>(int.MaxValue,-1), costs.Count) noticing the side effect, that the List was full of referenced copies to a single object. Changing an element like myList[i].First = 1 changed every single element in the whole List. It took me hours to find this bug. Do you guys know any solution to this issue (except for just using a common loop and use .Add(new Pair...)?Elasmobranch
@00zetti: It's not clear what point your comment is attempting to make.Codify
@JonSkeet Sry I missed the Shift button and posted it too early - see the edit ^^Elasmobranch
@00zetti: At that point, it's effectively asking an unrelated question. It should be in a new post, after checking for duplicates. You probably just want to use Enumerable.Range(...).Select(...).ToList() though.Codify
@JonSkeet This worked for me, thanks. I just thought it could be of general interest, since you might do not want references to the same object (what new intuitively didn't meaned to me).Elasmobranch
Useful to pad ArrayList when you need to InsertRange padding values so you can insert beyond the current size. By default the ArrayList would throw as it does not pad itself.Olgaolguin
@JeremyRayBrown : I noticed that you were trying to add a long edit to the existing answer. I'd suggest adding another answer, and comment here on this one with a link to your proposal.Rectifier
@Pac0, I just added an answer below. The edits can be disapproved.Deauville
L
204
List<string> L = new List<string> ( new string[10] );

See List(IEnumerable) constructor.

Lutes answered 10/3, 2009 at 20:4 Comment(6)
personally I think this is the cleanest way - although it was mentioned in the question body as potentially clumsy - don't know whyBrachycephalic
+1: Just hit a situation where I needed a variable size list to be initialised with a fixed set of nulls before populating via an index (and adding extras afterwards, so an array was unsuitable). This answer gets my vote for being practical and simple.Suicide
Fabulous answer. @GoneCoding I was just wondering whether internally the newly initialized list L will simply reuse the memory of string[10] as is (backing store of an lists is also an array) or it will allocate a new memory of its own and then copy the contents of string[10]? string[10] will get garbage collected automatically if L selects the later route.Zared
@Zared That is the only downside to this approach: The array will not be reused, so you will momentarily have two copies of the array (List uses arrays internally as you seem to be aware of). In rare cases that might be a problem if you have a huge number of elements, or memory constraints. And yes the extra array will be eligible for garbage collection as soon as the List constructor is done (it would have been a horrible memory leak otherwise). Note that eligible does not mean "collected right away", but rather the next time garbage collection runs.Steric
This answer allocates 10 new strings - then iterates over them copying them as required. If you're working with large arrays; then don't even consider this as it needs twice the memory than the accepted answer.Impeach
@Impeach This answer allocates an array, no strings (they are all null). The List constructor will treat the array like an ICollection, using its Count to initialize the internal array. A fake-implementation of ICollection just returning the Count and doing nothing else would be ideal, but I don't know of one.Symonds
C
106

I can't say I need this very often - could you give more details as to why you want this? I'd probably put it as a static method in a helper class:

public static class Lists
{
    public static List<T> RepeatedDefault<T>(int count)
    {
        return Repeated(default(T), count);
    }

    public static List<T> Repeated<T>(T value, int count)
    {
        List<T> ret = new List<T>(count);
        ret.AddRange(Enumerable.Repeat(value, count));
        return ret;
    }
}

You could use Enumerable.Repeat(default(T), count).ToList() but that would be inefficient due to buffer resizing.

Note that if T is a reference type, it will store count copies of the reference passed for the value parameter - so they will all refer to the same object. That may or may not be what you want, depending on your use case.

EDIT: As noted in comments, you could make Repeated use a loop to populate the list if you wanted to. That would be slightly faster too. Personally I find the code using Repeat more descriptive, and suspect that in the real world the performance difference would be irrelevant, but your mileage may vary.

Codify answered 21/1, 2009 at 21:0 Comment(15)
I realize this is an old post, but I am curious. Enumerable.Repeat fares much worse compared to a for loop, as per the last portion of the link (dotnetperls.com/initialize-array). Also AddRange() has O(n) complexity as per msdn. Isn't it a bit counter productive to use the given solution instead of a simple loop?Classicism
@Jimmy: Both approaches will be O(n), and I find this approach to be more descriptive of what I'm trying to achieve. If you prefer a loop, feel free to use it.Codify
@Jimmy: Also note that the benchmark there is using Enumerable.Repeat(...).ToArray(), which is not how I'm using it.Codify
@JonSkeet, I see that now. I did run some tests now, and for int lists the for loop runs slightly faster, but for decimal list your solution with repeat works slightly faster.Classicism
Don't really see the need for two separate overloads. Just declare it as public static List<T> Repeated(int count, TSource value = default(T)) instead.Steric
@AnorZaken: Well it's not really an overload given that it's a separate method name - and bear in mind that this answer was written in January 2009, before C# even had optional parameters...Codify
@JonSkeet technically correct as always. :P Well anyway I quite often try to add (what I hope is) useful comments to old answers for newcomers to find. It's not personal criticism. It's just that when googling comes up with old answers, it doesn't hurt to add a modern perspective. And the point is visibility - so for a small change a comment makes more sense than a new answer in my opinion. Because frankly, there's nothing inherently wrong with your answer. It's just a bit dated, as you said. Cheers! :)Steric
I've used the Enumerable.Repeat() in the following way (implemented Pair just like the C++ equivalent): Enumerable.Repeat( new Pair<int,int>(int.MaxValue,-1), costs.Count) noticing the side effect, that the List was full of referenced copies to a single object. Changing an element like myList[i].First = 1 changed every single element in the whole List. It took me hours to find this bug. Do you guys know any solution to this issue (except for just using a common loop and use .Add(new Pair...)?Elasmobranch
@00zetti: It's not clear what point your comment is attempting to make.Codify
@JonSkeet Sry I missed the Shift button and posted it too early - see the edit ^^Elasmobranch
@00zetti: At that point, it's effectively asking an unrelated question. It should be in a new post, after checking for duplicates. You probably just want to use Enumerable.Range(...).Select(...).ToList() though.Codify
@JonSkeet This worked for me, thanks. I just thought it could be of general interest, since you might do not want references to the same object (what new intuitively didn't meaned to me).Elasmobranch
Useful to pad ArrayList when you need to InsertRange padding values so you can insert beyond the current size. By default the ArrayList would throw as it does not pad itself.Olgaolguin
@JeremyRayBrown : I noticed that you were trying to add a long edit to the existing answer. I'd suggest adding another answer, and comment here on this one with a link to your proposal.Rectifier
@Pac0, I just added an answer below. The edits can be disapproved.Deauville
I
18

Use the constructor which takes an int ("capacity") as an argument:

List<string> = new List<string>(10);

EDIT: I should add that I agree with Frederik. You are using the List in a way that goes against the entire reasoning behind using it in the first place.

EDIT2:

EDIT 2: What I'm currently writing is a base class offering default functionality as part of a bigger framework. In the default functionality I offer, the size of the List is known in advanced and therefore I could have used an array. However, I want to offer any base class the chance to dynamically extend it and therefore I opt for a list.

Why would anyone need to know the size of a List with all null values? If there are no real values in the list, I would expect the length to be 0. Anyhow, the fact that this is cludgy demonstrates that it is going against the intended use of the class.

Idzik answered 21/1, 2009 at 20:56 Comment(6)
This answer does not allocate 10 null entries in the list (which was the requirement), it simply allocates space for 10 entries before a resize of the list is required (i.e. capacity), so this does nothing different to new List<string>() as far as the problem goes. Well done on getting so many up-votes though :)Suicide
that overloaded constructor is the "initial capacity" value not the "size" or "length", and it doesn't initialise the items eitherAlewife
To answer "why would someone need this": I need this right now for deep cloning tree data structures. A node might or might not populate its children, yet my base node class needs to be able to clone itself with all it's child nodes. Blah, blah it's even more complicated. But I need both to populate my still empty list via list[index] = obj; and to use some other list capabilities.Habitation
@Bitterblue: Also, any sort of pre-allocated mapping where you may not have all of the values up front. There are certainly uses; I wrote this answer in my less experienced days.Idzik
correct me if i'm wrong but this would be useful for optimizing the List.Add Method by avoid resizing the underlying store each time Add is called individually?Janeejaneen
@ShayanZafar .....Then literally use an array. You use lists to account for potential re-sizing. If the concern is optimization then you might as well discard the overhead that a List<T> comes with alsoSubcontract
M
14

Create an array with the number of items you want first and then convert the array in to a List.

int[] fakeArray = new int[10];

List<int> list = fakeArray.ToList();
Millenary answered 2/9, 2016 at 10:54 Comment(0)
D
10

If you want to initialize the List with N elements of some fixed value:

public List<T> InitList<T>(int count, T initValue)
{
    return Enumerable.Repeat(initValue, count).ToList();
}
Durning answered 21/1, 2009 at 21:24 Comment(1)
See John Skeet's answer for concern over buffer resizing by this technique.Durning
P
8

This is an old question, but I have two solutions. One is fast and dirty reflection; the other is a solution that actually answers the question (set the size not the capacity) while still being performant, which none of the answers here do.


Reflection

This is quick and dirty, and should be pretty obvious what the code does. If you want to speed it up, cache the result of GetField, or create a DynamicMethod to do it:

public static void SetSize<T>(this List<T> l, int newSize) =>
    l.GetType().GetField("_size", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(l, newSize);

Obviously a lot of people will be hesitant to put such code into production.


ICollection<T>

This solution is based around the fact that the constructor List(IEnumerable<T> collection) optimizes for ICollection<T> and immediately adjusts the size to the correct amount, without iterating it. It then calls the collections CopyTo to do the copy.

The code for the List<T> constructor is as follows:

public List(IEnumerable<T> collection) {
....
    ICollection<T> c = collection as ICollection<T>;
    if (collection is ICollection<T> c)
    {
        int count = c.Count;
        if (count == 0)
        {
            _items = s_emptyArray;
        }
        else {
            _items = new T[count];
            c.CopyTo(_items, 0);
            _size = count;
        }
    }    

So we can completely optimally pre-initialize the List to the correct size, without any extra copying.

How so? By creating an ICollection<T> object that does nothing other than return a Count. Specifically, we will not implement anything in CopyTo which is the only other function called.

private struct SizeCollection<T> : ICollection<T>
{
    public SizeCollection(int size) =>
        Count = size;

    public void Add(T i){}
    public void Clear(){}
    public bool Contains(T i)=>true;
    public void CopyTo(T[]a, int i){}
    public bool Remove(T i)=>true;
    public int Count {get;}
    public bool IsReadOnly=>true;
    public IEnumerator<T> GetEnumerator()=>null;
    IEnumerator IEnumerable.GetEnumerator()=>null;
}

public List<T> InitializedList<T>(int size) =>
    new List<T>(new SizeCollection<T>(size));

We could in theory do the same thing for AddRange/InsertRange for an existing array, which also accounts for ICollection<T>, but the code there creates a new array for the supposed items, then copies them in. In such case, it would be faster to just empty-loop Add:

public void SetSize<T>(this List<T> l, int size)
{
    if(size < l.Count)
        l.RemoveRange(size, l.Count - size);
    else
        for(size -= l.Count; size > 0; size--)
            l.Add(default(T));
}
Pyrogen answered 17/1, 2021 at 23:13 Comment(10)
Seeing that IEnumerable constructor really makes me wish for there to be one accepting a ReadOnlySpan<T>...Spook
See also https://mcmap.net/q/137898/-how-can-i-get-a-span-lt-t-gt-from-a-list-lt-t-gt-while-avoiding-needless-copies and learn.microsoft.com/en-us/dotnet/api/…Pyrogen
Yeah, I've been at that question before I came here. What I need is to initialize the internal buffer and Count manually as I already have the buffer in memory (read from a stream). CollectionsMarshal.AsSpan() only grabs a Span storing all items up to Count - which is 0 on new lists. :(Spook
So use my solution pre-size it, then grab the array using CollectionsMarshalPyrogen
It would definitely do its job. But as I need it only once, it's too much workaround, relying on the List implementation (even if it rarely if ever changes), adding a dummy class... I'll keep it kiss and simply iterate over my Span and Adding each element to a new List - until one day a constructor accepting Span may be added :o)Spook
Actually now that I think about it, you can just use the ICollection.CopyTo function which accepts an array, you can copy the Span straight into it.Pyrogen
That would copy data from the List to a Span, I need to make the Span the internal, initial buffer of the List. 🤔Spook
Well you could store a delegate that fills the array dotnetfiddle.net/QqY3yPPyrogen
@Charlieface: You can but then you have to do some hackery indeed to get a span to it.Engle
Depends where you get it from. The fiddle I show creates the span from an array on the outside. I admit this does cause the lambda to capture a variable, but it depends where you are getting it from as to whether that's a problem. Ultimately, this wasn't the original question so didn't go too far trying to work it out.Pyrogen
V
4

Why are you using a List if you want to initialize it with a fixed value ? I can understand that -for the sake of performance- you want to give it an initial capacity, but isn't one of the advantages of a list over a regular array that it can grow when needed ?

When you do this:

List<int> = new List<int>(100);

You create a list whose capacity is 100 integers. This means that your List won't need to 'grow' until you add the 101th item. The underlying array of the list will be initialized with a length of 100.

Venter answered 21/1, 2009 at 20:57 Comment(3)
"Why are you using a List if you want to initialize it with a fixed value" A good point.Idzik
He asked for a list in which each element was initialized and the list had a size, not just a capacity. This answer is incorrect as it stands now.Belomancy
The question requires an answer, not criticism of being asked. Sometimes there is a reason to do it this way, as opposed to using an array. If interested in why this might be the case, one can ask a Stack Overflow question for it.Onlybegotten
G
3

You seem to be emphasizing the need for a positional association with your data, so wouldn't an associative array be more fitting?

Dictionary<int, string> foo = new Dictionary<int, string>();
foo[2] = "string";
Georgia answered 23/1, 2009 at 13:30 Comment(1)
This is answering a different question to the one being asked.Onlybegotten
A
2

Initializing the contents of a list like that isn't really what lists are for. Lists are designed to hold objects. If you want to map particular numbers to particular objects, consider using a key-value pair structure like a hash table or dictionary instead of a list.

Ankylosaur answered 21/1, 2009 at 20:59 Comment(1)
This does not answer the question, but merely gives a reason for it not to be asked.Onlybegotten
D
2

The accepted answer (the one with the green check mark) has an issue.

The problem:

var result = Lists.Repeated(new MyType(), sizeOfList);
// each item in the list references the same MyType() object
// if you edit item 1 in the list, you are also editing item 2 in the list

I recommend changing the line above to perform a copy of the object. There are many different articles about that:

If you want to initialize every item in your list with the default constructor, rather than null, then add the following method:

public static List<T> RepeatedDefaultInstance<T>(int count)
{
    List<T> ret = new List<T>(count);
    for (var i = 0; i < count; i++)
    {
        ret.Add((T)Activator.CreateInstance(typeof(T)));
    }
    return ret;
}
Deauville answered 25/7, 2019 at 14:52 Comment(3)
It's not an "issue" - it's the normal behavior of copying references. Without knowing the situation, you can't know whether it's suitable to copy the object. The question isn't about whether or not lists should be populated with copies - it's about initializing a list with a capacity. I'll clarify my answer in terms of the behavior it does have, but I really don't think it counts as a problem in the context of this question.Codify
@JonSkeet, I was replying to the static helper, which is okay for primitive types but not reference types. A scenario where a list is initialized with the same referenced item doesn't seem right. In that scenario why even have the list if every item in it points to the same object on the heap.Deauville
Sample scenario: you want to populate a list of strings, initially with an entry of "Unknown" for every element, then you modify the list for specific elements. In that case it's entirely reasonable for all the "Unknown" values to be references to the same string. It would be pointless to clone the string each time. Populating a string with multiple references to the same object isn't "right" or "wrong" in a general sense. So long as readers know what the behavior is, it's up to them to decide whether it meets their specific use case.Codify
S
1
string [] temp = new string[] {"1","2","3"};
List<string> temp2 = temp.ToList();
Schott answered 21/1, 2009 at 21:5 Comment(3)
How about List<string> temp2 = new List<string>(temp); Like the OP already suggested.Idzik
Ed - this one actually does answer the question - which is not about capacity.Tessie
But the OP already stated that he did not like this solution.Idzik
P
1

You can use Linq to cleverly initialize your list with a default value. (Similar to David B's answer.)

var defaultStrings = (new int[10]).Select(x => "my value").ToList();

Go one step farther and initialize each string with distinct values "string 1", "string 2", "string 3", etc:

int x = 1;
var numberedStrings = (new int[10]).Select(x => "string " + x++).ToList();
Putumayo answered 24/11, 2014 at 19:15 Comment(0)
V
1

After thinking again, I had found the non-reflection answer to the OP question, but Charlieface beat me to it. So I believe that the correct and complete answer is https://mcmap.net/q/136285/-how-to-initialize-a-list-lt-t-gt-to-a-given-size-as-opposed-to-capacity

My old answer:

If I understand correctly, you want the List<T> version of new T[size], without the overhead of adding values to it.

If you are not afraid the implementation of List<T> will change dramatically in the future (and in this case I believe the probability is close to 0), you can use reflection:

    public static List<T> NewOfSize<T>(int size) {
        var list = new List<T>(size);
        var sizeField = list.GetType().GetField("_size",BindingFlags.Instance|BindingFlags.NonPublic);
        sizeField.SetValue(list, size);
        return list;
    }

Note that this takes into account the default functionality of the underlying array to prefill with the default value of the item type. All int arrays will have values of 0 and all reference type arrays will have values of null. Also note that for a list of reference types, only the space for the pointer to each item is created.

If you, for some reason, decide on not using reflection, I would have liked to offer an option of AddRange with a generator method, but underneath List<T> just calls Insert a zillion times, which doesn't serve.

I would also like to point out that the Array class has a static method called ResizeArray, if you want to go the other way around and start from Array.

To end, I really hate when I ask a question and everybody points out that it's the wrong question. Maybe it is, and thanks for the info, but I would still like an answer, because you have no idea why I am asking it. That being said, if you want to create a framework that has an optimal use of resources, List<T> is a pretty inefficient class for anything than holding and adding stuff to the end of a collection.

Vacua answered 12/9, 2020 at 13:35 Comment(0)
O
0

A notice about IList: MSDN IList Remarks: "IList implementations fall into three categories: read-only, fixed-size, and variable-size. (...). For the generic version of this interface, see System.Collections.Generic.IList<T>."

IList<T> does NOT inherits from IList (but List<T> does implement both IList<T> and IList), but is always variable-size. Since .NET 4.5, we have also IReadOnlyList<T> but AFAIK, there is no fixed-size generic List which would be what you are looking for.

Obi answered 9/11, 2016 at 9:27 Comment(0)
R
0

This is a sample I used for my unit test. I created a list of class object. Then I used forloop to add 'X' number of objects that I am expecting from the service. This way you can add/initialize a List for any given size.

public void TestMethod1()
    {
        var expected = new List<DotaViewer.Interface.DotaHero>();
        for (int i = 0; i < 22; i++)//You add empty initialization here
        {
            var temp = new DotaViewer.Interface.DotaHero();
            expected.Add(temp);
        }
        var nw = new DotaHeroCsvService();
        var items = nw.GetHero();

        CollectionAssert.AreEqual(expected,items);


    }

Hope I was of help to you guys.

Renick answered 20/11, 2016 at 15:48 Comment(0)
H
0

With .NET 8 CollectionsMarshal.SetCount<T>(List<T>, Int32) method was introduced which does exactly that in performant manner (implementation):

Sets the count of the List<T> to the specified value.
When increasing the count, uninitialized data is being exposed.

var ints = new List<int>();
CollectionsMarshal.SetCount(ints, 20);
Console.WriteLine(ints.Count); // Prints "20"

Which should be more performant due to reduced allocations.

Helm answered 23/1, 2024 at 19:14 Comment(0)
G
0

Building on @jon-skeet's answer, here is a helper function that will generate a list of specified length with optional value parameter:

public static List<T> NewSizedList<T>(int n, T v = default(T))
{
    List<T> ret = new List<T>(n);
    ret.AddRange(Enumerable.Repeat(v, n));
    return ret;
}
Glycogen answered 20/4, 2024 at 16:52 Comment(0)
T
-2

A bit late but first solution you proposed seems far cleaner to me : you dont allocate memory twice. Even List constrcutor needs to loop through array in order to copy it; it doesn't even know by advance there is only null elements inside.

1. - allocate N - loop N Cost: 1 * allocate(N) + N * loop_iteration

2. - allocate N - allocate N + loop () Cost : 2 * allocate(N) + N * loop_iteration

However List's allocation an loops might be faster since List is a built-in class, but C# is jit-compiled sooo...

Terce answered 30/11, 2016 at 1:9 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.