ObservableCollection's IEnumerable ctor finalizes collection, but the IList ctor does not

In the following method, when I copy the IEnumerable result to a list with ToList(), no finalizers are called at the ObservableCollection's IList constructor, and the IDisposable view-models only get finalized upon program closure:

private void ReadHeaders()
{
    IList<PlanningGridHeaderVM> viewModelSet =
        (from header in _planningGridService.ReloadHeaders().OrderBy(x => x.PlanNumber)
         select new PlanningGridHeaderVM((PlanningGridHeader)header)).ToList();

    foreach (PlanningGridHeaderVM headerVM in viewModelSet)
    {
        ItemEditedEventManager.AddHandler(headerVM, OnItemEdited);
        PropertyChangedEventManager.AddHandler(headerVM, OnPropertyChanged, string.Empty);
    }

    this.ViewModels = new ObservableCollection<PlanningGridHeaderVM>(viewModelSet);
    CollectionChangedEventManager.AddHandler(this.ViewModels, this.OnCollectionChanged);
}

However, when I use the IEnumerable result directly in the ObservableCollection's IEnumerable constructor, my Debug output informs me that all of the IDisposable view-model items are being finalized by the GC at that point (this is what puzzles me).

Nevertheless, I still get the desired collection on-screen, and upon program closure, they all get finalized again (this time, as expected):

private void ReadHeaders()
{
    IEnumerable<PlanningGridHeaderVM> viewModelSet =
        (from header in _planningGridService.ReloadHeaders().OrderBy(x => x.PlanNumber)
         select new PlanningGridHeaderVM((PlanningGridHeader)header));

    foreach (PlanningGridHeaderVM headerVM in viewModelSet)
    {
        ItemEditedEventManager.AddHandler(headerVM, OnItemEdited);
        PropertyChangedEventManager.AddHandler(headerVM, OnPropertyChanged, string.Empty);
    }

    this.ViewModels = new ObservableCollection<PlanningGridHeaderVM>(viewModelSet);
    CollectionChangedEventManager.AddHandler(this.ViewModels, this.OnCollectionChanged);
}

Why? The MSDN pages for both (here and here) say "The elements are copied onto the ObservableCollection in the same order they are read by the enumerator of the collection."

Jon Skeet
people
quotationmark

In the second case, you're actually evaluating the query twice. Once when you use foreach, and then another time when you create the ObservableCollection. You'll end up with two distinct sets of objects, which you could validate by adding some debug information in the PlanningGridHeaderVM constructor.

Iterating over the query results the first time doesn't actively finalize it - there's no such concept. However, the objects returned will be immediately eligible for garbage collection unless your AddHandler methods retain a reference to them.

In the first case, you're only evaluating the query once, because ToList() will materialize the query. It's basically taking the query, evaluating it and remembering the results - so then when you iterate over it with foreach and then create an ObservableCollection from it, both of those loops will operate on the same collection of objects.

people

See more on this question at Stackoverflow