views:

127

answers:

3
public IEnumerable<ModuleData> ListModules()
{
    foreach (XElement m in Source.Descendants("Module"))
    {
        yield return new ModuleData(m.Element("ModuleID").Value);
    }
}

Initially the above code is great since there is no need to evaluate the entire collection if it is not needed.

However, once all the Modules have been enumerated once, it becomes more expensive to repeatedly query the XDocument when there is no change.

So, as a performance improvement:

public IEnumerable<ModuleData> ListModules()
{
    if (Modules == null)
    {
        Modules = new List<ModuleData>();
        foreach (XElement m in Source.Descendants("Module"))
        {
            Modules.Add(new ModuleData(m.Element("ModuleID").Value, 1, 1));
        }
    }
    return Modules;
}

Which is great if I am repeatedly using the entire list but not so great otherwise.

Is there a middle ground where I can yield return until the entire list has been iterated, then cache it and serve the cache to subsequent requests?

+4  A: 

You can look at Saving the State of Enumerators which describes how to create lazy list (which caches once iterated items).

Dzmitry Huba
very cool! thanks for the link this totally solved a similar problem i was having with a query that read from disk.
luke
A: 

I don't see any serious problem with the idea to cache results in a list, just like in the above code. Probably, it would be better to construct the list using ToList() method.

public IEnumerable<ModuleData> ListModules()
{
    if (Modules == null)
    {
        Modules = Source.Descendants("Module")
                      .Select(m => new ModuleData(m.Element("ModuleID").Value, 1, 1)))
                      .ToList();
    }
    return Modules;
}
Gart
That's much tidier that mine but calling ToList() iterates the entire enumerable anyway so it doesn't solve my problem.
Daniel Skinner