initialize list collection

T

tshad

If I have a list collection that I set up and use and then want to
re-initialize it, can I just do a "new" again or do I need to get rid of it
first.

For example:

If I have a PropertyForeignKey class, which is just a list of properties and
I have another class:

public class PropertyForeignKeyCollection : List<PropertyForeignKey> { }

I can do this:
PropertyForeignKeyCollection propertyForeignkeys = new
PropertyForeignKeyCollection();

propertyForeignkeys.add(...)
propertyForeignkeys.add(...)
propertyForeignkeys.add(...)
....

Now I want to clear the collection and use the object again.

Can I do this:

PropertyForeignKeyCollection propertyForeignkeys = new
PropertyForeignKeyCollection();

Will this create a new object and the old one will get taken care of by the
Garbage collector or do I need to get rid of it myself?

Thanks,

Tom
 
T

tshad

Peter Duniho said:
[...]
Now I want to clear the collection and use the object again.

Can I do this:

PropertyForeignKeyCollection propertyForeignkeys = new
PropertyForeignKeyCollection();

Will this create a new object and the old one will get taken care of by
the
Garbage collector or do I need to get rid of it myself?

Calling "new" will create a new object (that's what it always does for
reference types), and assigning that reference to your variable will cause
the reference in that variable to the old instance to no longer exist. If
that was the last reference making the collection class reachable, then
the GC will eventually reclaim the memory used by that instance (that's
what the GC always does).
That was what I thought, but wasn't sure.
Note that List<T> has a Clear() method, which you could use if all you
want to do is empty the collection. Assuming each use of the instance is
likely to need about the same capacity as the other uses, this would be
somewhat more efficient.
Why is that more efficient? If I usually have about 1000 items in the list
and call Clear(), does it keep the whole list around just blanked out?

Thanks,

Tom
 
T

tshad

Peter Duniho said:
[...]
Note that List<T> has a Clear() method, which you could use if all you
want to do is empty the collection. Assuming each use of the instance
is
likely to need about the same capacity as the other uses, this would be
somewhat more efficient.
Why is that more efficient? If I usually have about 1000 items in the
list
and call Clear(), does it keep the whole list around just blanked out?

Yes. Internally, List<T> uses an array to store your data. It starts out
with four elements, and then doubles its capacity each time you exceed the
current capacity. If you have 1000 items in the list, then it will have a
capacity of 1024, having reallocated the array eight times. When you call
Clear(), the capacity isn't reduced, so you still have an array of 1024
elements in it, ready to be populated with brand-new elements.
I see, but if I do this - would the items I don't use be nulls? What about
adding to the list - *.Add? How would that work? When you say has the
Capacity of 1024 are you say it has the space reserved but that there are no
list elements actually there?

Thanks,
 
T

tshad

Peter Duniho said:
I see, but if I do this - would the items I don't use be nulls? What
about
adding to the list - *.Add? How would that work? When you say has the
Capacity of 1024 are you say it has the space reserved but that there
are no
list elements actually there?

It's an array. There are always as many elements in the array as the
capacity of the list; that's what the capacity is.

But, the List<T> class uses other member fields to keep track of what
elements in the array are actually used. It shouldn't matter to you what
is stored in the unused elements of the array, but yes...they are nulls
(for reference types) or the default value (for value types).

You can use Reflector or download the code from Microsoft to examine the
implementation more closely if you really care. But, the basic idea is
that there's an array, and a counter to keep track of how many elements
are actually in the List<T>. For example:

class List<T>
{
private T[] _rgt; // actual storage
private int _ct; // number of elements used so far
}

If you add an element and the counter is already equal to the length of
the array, List<T> will create a new array, copy the elements from the
original array to the new array, and then replace the reference to the
original array with the reference to the new array, before it adds your
new element. For example:

void Add(T t)
{
if (_ct == _rgt.Length)
{
Array.Resize(ref _rgt, _rgt.Length * 2);
}

_rgt[_ct++] = t;
}

In either case, the addition of the element is simply copying the element
to the element in the array just after the last used element and updating
the count of used elements accordingly.

When you call Clear(), List<T> goes through the entire array to reset all
the element values to their default values. This ensures that the array
inside List<T> doesn't hang on to any references that your code expects to
no longer exist. But it doesn't reallocate the array itself. It just
sets the count of used elements back to zero.
Makes sense.

Thanks,

Tom
 
J

Jon Skeet [C# MVP]

Peter Duniho said:
Calling "new" will create a new object (that's what it always does for
reference types)

Very nearly always, anyway. A while ago I found one exception to this
rule. It's not normal string interning, and as far as I can see it only
happens in this precise case:

using System;

class Test
{
static void Main()
{
string x = new string(new char[0]);
string y = new string(new char[0]);
Console.WriteLine(object.ReferenceEquals(x, y)); // True
}
}

Weird stuff. Irrelevant to the actual question, but I thought you might
find it interesting...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top