Lots of Continues in an Inner Loop and Dictionary of Actions I'm using ABCPDF (Version 8) to update an existing PDF document and I believe its API is hurting me in this situation and was curious whether anyone had any comments on how this looks as it appears ugly to me.

The situation: I am replacing pages in PDF documents that are all generated by an in-house process so I can rely on their format being consistent and the following code is tasked with updating annotation links on the Table of Contents page(s) to point to the replace pages instead of the old pages. Since there can be multiple replacement operations, I decided to put the collection of these link annotations into a dictionary instead of looping through all of them for each replacement operation.

As my comments in the code mention, I only was able to piece this together by debugging a lot and examining the properties of different ABCPDF objects.

Here's the relevant code:

//use less than or equal to here because a one page TOC will have a matching start and end page number
private Dictionary&lt;int, Action&lt;int&gt;&gt; _linkUpdates;
WebSuperGoo.ABCPDF8.Doc pdfDoc;
for (var pageNumber = startPageNumber; pageNumber &lt;= endPageNumber; pageNumber++)
{
    pdfDoc.PageNumber = pageNumber;
    var annotCount = pdfDoc.GetInfoInt(pdfDoc.Page, "Annot Count");

    //this is really ugly code that looks for link annotations (i.e. links in the TOC) that reference our old page Id
    //it depends on some nasty PDF data structures in ABCPDF and assumes they will always appear the same way
    //it took me a few hours of debugging to figure out how to get at this stuff and modify it, not pleasant
    for (var i = 1; i &lt;= annotCount; i++)
    {
        //if at any level we come up empty, just get out of this annotation and try the next one
        var annotId = pdfDoc.GetInfoInt(pdfDoc.Page, string.Format("Annot {0}", i));
        var annotationMaster = (Annotation)pdfDoc.ObjectSoup[annotId];
        if (annotationMaster.SubType != "Link")
        {
            continue;
        }
        var annotItem = annotationMaster.Resolve(Atom.GetItem(annotationMaster.Atom, 0)) as DictAtom;
        if (annotItem == null)
        {
            continue;
        }
        var destination = annotItem["D"] as ArrayAtom;
        if (destination == null)
        {
            continue;
        }
        var destinationPage = destination[0] as RefAtom;
        if (destinationPage == null)
        {
            continue;
        }
        _linkUpdates.Add(destinationPage.ID,
            updatedPageId =&gt;
            {
                destinationPage.ID = updatedPageId;
                Atom.SetItem(destination, 0, destinationPage);
            }
        );
    }
}


I included the declarations of _linkUpdates and doc for reference. So after I have this collection populated, when I have an update to make, I can simply do this:

if (_linkUpdates.ContainsKey(oldPageId))
{
     _linkUpdates[oldPageId](newPageId);
}


I fully understand that this logic is heavily dependent on an understanding of how ABCPDF works, but since there's a fairly active community on SO, I figured this might get some responses, perhaps from somebody who knows of an easier way of getting at/updating these link annotations.

So, to summarize the areas I am interested in feedback on are:


The prevalence of continues in my inner for loop
The choice of using a dictionary with an Action value to update the related ABCPDF object


This does work fine, and I am operating in an environment where I will have at most 70 possible link annotations to consider.
If you do this often, you could write an extension method for object that takes a function, which is executed only when the input is not null. You could then use it in a fluent manner to navigate multiple times:

public static class Navigator
{
    public static TOutput Navigate&lt;TInput, TOutput&gt;(
        this TInput input, Func&lt;TInput, TOutput&gt; navigationFunction)
        where TOutput : class
    {
        if (input == null)
            return null;

        return navigationFunction(input);
    }
}


Usage:

var destinationPage = 
    (annotationMaster.Resolve(Atom.GetItem(annotationMaster.Atom, 0)) as DictAtom)
        .Navigate(annotItem =&gt; annotItem["D"] as ArrayAtom)
        .Navigate(destination =&gt; destination[0] as RefAtom);

if (destinationPage == null)
    continue;


Notice that I also removed the braces. This is a matter of personal opinion (and sometimes company policy), but I think that they're not always necessary, especially when the body of the condition is this simple.