In a tidy bit of paralipsis, I’m not going to mention “closures”, “currying”, or “partial function application” again. Instead, I will provide a real-world example of what you can do with C# 3.0 and how it can help solve your problems.

I will use Visio in this example because I am familiar with writing code to automate it, but you won’t need any knowledge about Visio to understand this post.

Let’s start off what the output I want. Simply this will be a rectangle with a circular gradient fill that goes from red to blue:

image

If I manually draw this in Visio 2007 it will look like this:

image

Now, what I want to do is to programmatically draw this shape instead of manually drawing it. So I write this code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IVisio = Microsoft.Office.Interop.Visio;

namespace DemoCurrying
{
    class Program
    {
        static void Main(string[] args)
        {
            var visapp = new Microsoft.Office.Interop.Visio.ApplicationClass();
            var doc = visapp.Documents.Add("");
            var page = visapp.ActivePage;
            var shape1 = page.DrawRectangle(2, 2, 6, 8);
            setfill1(shape1);
        }

        static void setfill1(IVisio.Shape shape)
        {
            // set the fill foreground color to red
            shape.get_CellsSRC(
                (short)IVisio.VisSectionIndices.visSectionObject,
                (short)IVisio.VisRowIndices.visRowFill,
                (short)IVisio.VisCellIndices.visFillForegnd)
                .FormulaU = "RGB(255,0,0)";

            // set the fill background color to blue
            shape.get_CellsSRC(
                (short)IVisio.VisSectionIndices.visSectionObject,
                (short)IVisio.VisRowIndices.visRowFill,
                (short)IVisio.VisCellIndices.visFillBkgnd)
                .FormulaU = "RGB(0,0,255)";

            // set the fill background pattern to radial
            shape.get_CellsSRC(
                (short)IVisio.VisSectionIndices.visSectionObject,
                (short)IVisio.VisRowIndices.visRowFill,
                (short)IVisio.VisCellIndices.visFillPattern)
                .FormulaU = "40";

        }

}

Let’s take a moment to examine the setfill1() method and see what we notice about it…

  • It takes a shape object as input
  • it sets the fill foreground to red, the background to blue, and the pattern to a radial fill
  • properties are identified using three values together ( a section index, a row index, and a cell index)
  • All three fill properties share the same section index and row index
  • it uses a method on the shape object called get_CellsSRC
  • it does a lot of casting of enums to “short”
  • It’s very repetitive

Now let’s focus on the repetitive parts. These are highlighted in red…

image

The parts that are not repeated are essentially the cell index and the value for the cell:

  • IVisio.VisCellIndices.visFillForegnd , "RGB(255,0,0)"
  • IVisio.VisCellIndices.visFillBkgnd, "RGB(0,0,255)"
  • IVisio.VisCellIndices.visFillPat, “40”

In generally we don’t want to repeat ourselves in code. What we do want in this case is to minimize our code to the unique parts (the three pairs of values shown above).

So what are our options?

  • Option #1 We could make a new class that helps reduce this effort
  • Option #2 We could create a special helper function called “set_fill_cell_formula”
  • Option #3 We could just have an array of the cell indices and the cell values and use a loop to set them
  • Option #4 We could take advantage of the new functional programming features in C#

I’ll focus on Option #4 only because it will illustrate how to use the new C# features. No criticism is implied against the other options.

In some sense, essentially what we are going to do is create a new function at runtime. This function will “remember” repetitive parts (shape, section index, row index), allowing us to worry about the non-repetitive parts.

Attempt #1

It’s imagine what we want to final code to look like

static void setfill3(IVisio.Shape shape)
{
    var func_set_cell = MAKE_SETCELLFORMULA_WITH_SHAPE_SEC_ROW(shape, IVisio.VisSectionIndices.visSectionObject, IVisio.VisRowIndices.visRowFill);
    func_set_cell(IVisio.VisCellIndices.visFillForegnd, "RGB(255,0,0)"); // set the fill foreground color to red
    func_set_cell(IVisio.VisCellIndices.visFillBkgnd, "RGB(0,0,255)"); //set the fill background color to blue
    func_set_cell(IVisio.VisCellIndices.visFillPattern, "40"); // set the fill background pattern to radial
}

the first line in red creates a new function that “remembers” the repetitive parts (the shape, the section index, and the row index). The new function is stored in a variable called “func_set_cell”

And then in the remaining  three lines we call func_set_cell with just the unique pieces of data to get the same effect

Now what about this method called “MAKE_SETCELLFORMULA_WITH_SHAPE_SEC_ROW”? How can it dynamically create a new function that remembers these parameters?

static Action<IVisio.VisCellIndices, string> MAKE_SETCELLFORMULA_WITH_SHAPE_SEC_ROW(IVisio.Shape shape, IVisio.VisSectionIndices sectionindex, IVisio.VisRowIndices rowindex)
{
    Action<IVisio.VisCellIndices, string> new_action =
        (IVisio.VisCellIndices cellindex, string value) =>
        {
            var cell = shape.get_CellsSRC((short)sectionindex, (short)rowindex, (short)cellindex);
            cell.FormulaU = value;
        }
    ;

    return new_action;
}

 

Attached Source code

  • The full visual studio project is here: DemoCurrying.zip
  • The project contains the code above and shows several variations that accomplish the same thing

Parting Thoughts

  • I hope this real-world example was useful in showing you the new features in C# 3.0 can help you with your own code
  • I do *NOT* suggest using this pattern at every opportunity. All of the options have pros & cons – the right choice for you is relevant to your circumstances, constraints, and and the problems you are trying to solve
  • For those of you automating Visio in C#, please keep in mind in real-world code I would normally use the Page objects SetFormulas() method which is far more complicated but also far faster than a series of individual calls to retrieve cells and set the formulas