Make this C# code more DRY public sealed class LinkXPathRepository : ILinkXPathRepository
{
    private static readonly ILog _log = LogManager.GetLogger(typeof(LinkXPathRepository));

    internal ILink Parse(Uri endpoint)
    {
        if (endpoint == null)
        {
            throw new ArgumentNullException("endpoint");
        }
        string leftPart = endpoint.GetLeftPart(UriPartial.Authority);

        EntityDataModelContext dc = DataContext.GetDataContext();

        IList&lt;LinkXPath&gt; sources = null;
        HtmlDocument document = null;

        Task t1 = Task.Factory.StartNew(() =&gt; sources = dc.LinkXPaths.Where(p =&gt; leftPart.Contains(p.Host)).OrderByDescending(p =&gt; p.Priority).ToList());
        Task t2 = Task.Factory.StartNew(() =&gt; document = Utility.DownloadHtml(endpoint));
        Task.WaitAll(new[] { t1, t2 });

        if (document == null)
        {
            return null;
        }

        Link result = new Link();
        foreach (LinkXPath source in sources)
        {
            if (result.Title.NullOrEmpty())
            {
                string title = GetFragment(document, source.Title);
                result.Title = title;
            }
            if (result.Description.NullOrEmpty())
            {
                string description = GetFragment(document, source.Description);
                result.Description = description;
            }
            if (result.Article.NullOrEmpty())
            {
                string article = GetFragment(document, source.Article);
                result.Article = article;
            }
        }

        return result;
    }

    internal string GetFragment(HtmlDocument document, string xpath)
    {
        return document.DocumentNode.GetChildNodeHtml(xpath);
    }
}


I'm particularly interested in refactoring this fragment:

            if (result.Title.NullOrEmpty())
            {
                string title = GetFragment(document, source.Title);
                result.Title = title;
            }
            if (result.Description.NullOrEmpty())
            {
                string description = GetFragment(document, source.Description);
                result.Description = description;
            }
            if (result.Article.NullOrEmpty())
            {
                string article = GetFragment(document, source.Article);
                result.Article = article;
            }


EDIT: please note that result.X and source.X come from different classes, even though their names are the same.
I propose this:

internal ILink Parse(Uri endpoint) {
    ...
    foreach (LinkXPath source in sources) {
        UpdateIfNecessary(document, ref result.Title, () =&gt; GetFragment(document, source.Title));
        UpdateIfNecessary(document, ref result.Description, () =&gt; GetFragment(document, source.Title));
        UpdateIfNecessary(document, ref result.Article, () =&gt; GetFragment(document, source.Article));
    }
    ...
}

private static void UpdateIfNecessary(Document document, ref string field, Func&lt;string&gt; getValue) {
    if(!string.IsNullOrEmpty(field)) {
        return;
    }
    field = getValue();
}


UpdateIfNecessary receives a lambda so it only evaluates the new value if necessary.

The field is passed by reference, so any change to the parameter in the method is reflected in the underlying argument variable in the calling method.