.NET

Write Reusable Code With Function Pointers – Avoid Repeating Yourself!

Posted on Updated on

I’ve been aware of function pointers for a couple decades now, but they seemed abstract and, well, hard to use. I finally put them to good use in my latest project. My benefits were 1) less repeated code and 2) fixing a bug that resulted from writing (essentially) the same code 10 times, but screwing-up once. Yippee! I got to use a cool feature and make my code better too.

The Problem We Want to Solve: Repeated Code

Imagine this: your project has at least 10 grids to display data which you can also export. Your  users all love Excel because they love to analyze their data with fancy statistics.  We help the users by allowing them to export their grid data to CSV files, giving them the option to launch in Excel.  Since we are considerate coders, we export their data with a nice header section showing details like location, name, date, etc. which is above and  beyond the mere row and column data.

So, we wrote 10 custom export functions that have a lot in common. Every function asks our users the same two questions (where to save, whether to launch in Excel), and does the actual work of opening the file and saving user’s data. The only thing different btween the 10 functions is the output header. I hate repeated code (you should too!), so we want a way to consolidate the repeated parts . If only we had a way to write a universal  export function with customizable head output!

My solution:

  1. Write a universal CSV export function
  2. Which takes a function pointer as input
  3. That function pointer will control to write each individual header format

What the Heck is a ‘Function Pointer’?

If you read Microsoft documentation, you may never see my term “function pointer”; Microsoft uses the term “delegate”. Since I’m old-fashioned, I have been loosely tossing-around the term “function pointers” because it has the same purpose. Whatever you call it, .NET implements my concept by two techniques:

  1. Action<T>
  2. Func<TResult>

Core concept: you use either of the things above to create a function variable that you can pass around like any other variable. Sometimes we use the term “first class function” to refer to the idea that you can store, assign, return, etc. these variables. Question: when do you use an Action vs. a Func? Answer: if you need to return a value, use Func, otherwise Action is simpler. Both have variations to allow a lot more parameters (e.g. Action<T1,T2,T3,T4… T16>.

Sample Action<T>:

//Build an action that will write some data to a stream writer 'sw'
 Action<StreamWriter> printFunc = (sw) => {
     sw.WriteLine("Elevation Band:,{0}", _LocationName);
     sw.WriteLine("Date,Value");
     sw.WriteLine("----,-----");
     foreach (TimeSeriesPoint tsp in _ObservedValues) {
         sw.WriteLine("{0},{1}", tsp.TsDate, tsp.TsValue);
     }
 };

// Invoke the function with a stream writer we built somewhere else:
printFunc(someStreamWriter);

The sample shows how to

  1. Declare a variable “printFunc”
  2. Which takes an input parameter “sw”, a StreamWriter
  3. And uses sw to print some class-level variables, namely, ‘_LocationName’ and ‘_ObservedValues’. Don’t worry about what these variables represent, trust me, they are just data and irrelevant to the main concept
  4. Finally, executing the code is as simple as executing any other function, just type the name (in this case, ‘printFunc’) and pass the parameter

Read the rest of this entry »