Working over OpenXml, I've came across this article: How to: Merge two adjacent cells in a spreadsheet document (Open XML SDK).
There is a code sample there, that I wanted to refactor. Here is its part:
// Insert a MergeCells object into the specified position.
if (worksheet.Elements<CustomSheetView>().Count() > 0)
{
     worksheet.InsertAfter(mergeCells, 
                           worksheet.Elements<CustomSheetView>().First());
}
else if (worksheet.Elements<DataConsolidate>().Count() > 0)
{
     worksheet.InsertAfter(mergeCells, 
                           worksheet.Elements<DataConsolidate>().First());
}
else if (worksheet.Elements<SortState>().Count() > 0)
{
     worksheet.InsertAfter(mergeCells, 
                           worksheet.Elements<SortState>().First());
}
//...and 5 more 
The best thing I managed is an extension method:
public static bool InsertElementAfter<T>(this Worksheet worksheet, 
                                              OpenXmlElement element)
    where T : OpenXmlElement
{
    if (!worksheet.Elements<T>().Any())
        return false;
    else
    {
        worksheet.InsertAfter(element, worksheet.Elements<T>().First());
        return true;
    }
}
But its usage looks as much terrible as the original code:
if (!worksheet.InsertElementAfter<CustomSheetView>(mergeCells))
    if (!worksheet.InsertElementAfter<DataConsolidate>(mergeCells))
        if (!worksheet.InsertElementAfter<SortState>(mergeCells))
            //...and 5 more
If I could somehow declare an array (or something) of type parameters, I would be able to write something like this:
foreach (var T in typeParameterList)
{
    if (worksheet.InsertElementAfter<T>(mergeCells))
        break;
}
But I do not know any way to do this.
So what are my options?
You could create a fluent API for this. The result could allow code like this:
worksheet.InsertAfter<CustomSheetView>(mergeCells)
         .Or<DataConsolidate>()
         .Or<SortState>();
There are two advantages to this fluent API:
The implementation of the API would require a class that holds the values and the Or() method:
public class ChainedElementInserter
{
    OpenXmlElement _element;
    Worksheet _worksheet;
    bool _previousResult;
    // ctor that initializes all three fields goes here.
    public ChainedElementInserter Or<T>()
        where T : OpenXmlElement
    {
        if (!_previousResult)
            _previousResult = _worksheet.InsertElementAfter<T>(_element);
        return this;
    }
}
The InsertAfter extension method starts this chain and looks like so:
public static ChainedElementInserter InsertAfter<T>(this Worksheet worksheet, 
                                  OpenXmlElement element)
    where T : OpenXmlElement
{
    return new ChainedElementInserter(
        worksheet, element, worksheet.InsertElementAfter<T>(element));
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With