views:

43

answers:

1

Now I'm not really sure what the problem here is but it seems that Linq quaries are re-evaluated each iteration wich is a effect I wan't here. However for some reason he skips elements he shouldn't when he does so.

Can someone help me understand what's going on here. Here is the Linq-to-XML code:

var contents = (from sdt in document.MainDocumentPart.RootElement.Descendants<SdtElement>()
                            select sdt);

            foreach (SdtElement item in contents)
            {
                ReplaceContent(item, data);
            }

The ReplaceContent method rips a part of the SdtElement out and puts it instead of that element. Next iteration contents has 1 less element as expected. However when I hit one paragraph (so 2 elements under the same parent) with 2 SdtElements and after he replaces the first one he doesn't include the second one and skips it. It's still in the document though.

Here is a part of the ReplaceContent method:

public void ReplaceContent(SdtElement contentControl, XElement xml)
    {
        OpenXmlElement content = null;

        if (contentControl is SdtRun)
        {
            content = (contentControl as SdtRun).SdtContentRun.GetFirstChild<Run>();
            //Items cut for brevity
        }
        //Items cut for brevity
        if (content != null)
        {
            content.Remove();
            var parent = contentControl.Parent;
            parent.ReplaceChild(content, contentControl);
        }
    }

I could use the toList() method on the Linq but then I'd had to change some other code a little. That's not really a problem I just rather would wan't it to work like this and also understand what it is that's going on here.

+2  A: 

LINQ queries get re-evaluated on each use because this allows them to be minimal in memory (generally O(1) memory use) and fast to return the first result.

In those cases where it's not a problem, it's by far the best way to go.

In those cases where it is a problem, use toList() or similar to get by.

A middle ground is to build an enumerable which passes through results for immediate processing, but which also maintains a list for subsequent work. This can be particularly useful if the first pass-through may result in the next operations being abandoned as unnecessary.

Jon Hanna
Thanks for the info. Do you know why he would ignore the specific elements in re-evaluation. In this case he ingores any that has the same parent as the iteration changed before.
Ingó Vals
Oh and could you explain the enumarable approach a bit more with a short example perhaps?
Ingó Vals
As far as I can see, you are altering the source between iterations, though I could be wrong on that. If so, that would explain the changes with each iteration. As for the enumerable approach you need to build a class that wraps an enumerator and in its own enumerator either returns from an internal store or, if the store is exhausted, takes from the wrapped enumerator and puts it in the internal store before returning it. I don't think it'd be useful here, but it can be in some cases.
Jon Hanna
You are correct, I am altering the source. However their are some elements that are still fulfilling the original query wich are being ignored and jumped over and others that aren't. Is that normal behaviour?
Ingó Vals