Replicating F#’s using Function in C#

Update – 5 April 2014

I’ve reconsidered the approach discussed here. This post is still worth reading for the context and motivation behind creating a Using method in C# but the updated approach works better and passes static code analysis. You can find the updated approach at the address below:

http://davefancher.com/2014/04/05/revisiting-the-using-function/

Thanks!

It didn’t take long for me to really appreciate the power offered by F#’s using function. Properly managing IDisposable instances in C# isn't particularly problematic but the using statement really doesn't offer a whole lot in the way of flexibility.  Sure, the block lets you create and dispose some IDisposable instance and put some arbitrary code within it but even before I entered the world of functional programming I found the syntax clunky, particularly when I only want the instance around long enough to get some value from it so I can do something with that value later. The obvious solution to the problem is to just use F# instead but unfortunately that's not always a viable option in this C# dominated market.

Assuming that I have to work in C# I could address the situation by just putting all the code in the using block.

// C#
using(var img = Image.FromFile(@"C:\Windows\Web\Screen\img100.png"))
{
  Console.WriteLine("Dimensions: {0} x {1}", img.Width, img.Height);
}

Granted, in this contrived example I'm only writing the dimensions to the console so the image would be disposed quickly but what if I needed those dimensions somewhere else? There are a few approaches to take and honestly, I don't like any of them all that much.

The first way would be to forego using altogether.

// C#
var img = Image.FromFile(@"C:\Windows\Web\Screen\img100.png");
var dims = Tuple.Create(img.Width, img.Height);
img.Dispose();

// Do something with dims elsewhere

This approach is probably the cleanest and is very similar to a use binding in F# but it requires discipline to remember to manually dispose of the object. In C# I'm so conditioned to define IDisposables within using blocks though that I seldom take this approach. In order to do this same task with a using statement there are basically two options, define a variable outside of the block and assign it inside the block or define a method to wrap the using statement. I generally prefer the later because it facilitates reuse and eliminates a state change.

Variable approach

// C#
Tuple<int, int> dims;
using(var img = Image.FromFile(@"C:\Windows\Web\Screen\img100.png"))
{
  dims = Tuple.Create(img.Width, img.Height);
}

// Do something with dims elsewhere

Method approach

// C#
private Tuple<int, int> GetDimensions()
{
  using(var img = Image.FromFile(@"C:\Windows\Web\Screen\img100.png"))
  {
    return Tuple.Create(img.Width, img.Height);
  }
}

// Do something with dims elsewhere

Now let's see how this same example would look in F# with the using function.

// F#
let dims = using (Image.FromFile(@"C:\Windows\Web\Screen\img100.png"))
                 (fun img -> (img.Width, img.Height))

Look how clean that is! Wouldn't it be nice to have something like that in C#? You've probably guessed if from nothing else than the title of this article that it's entirely possible. Right now you might be thinking that you could just reference FSharp.Core and call the function from the Operators module but you'll quickly find that more trouble than it's worth. The using function's signature is:

// F#
val using : resource:'T -> action:('T -> 'U) (requires 'T :> System.IDisposable)

The function accepts two arguments: resource, a generic argument constrained to IDisposable, and action, a function that accepts 'T and returns another (unconstrained) generic type, 'U. That second argument is what would prove problematic if you tried to call the function from C# since it compiles to FSharpFunc<T, TResult> instead of Func<T, TResult>. Fortunately though it's really easy to replicate the functionality natively in C#.

Due to differences between C# and F# the C# version of the Using function needs to be overloaded to accept either a Func or an Action depending on whether you're returning a value. You'll see though that in either case the function is just wrapping up the provided IDisposable instance inside a using statement and invoking the delegate, passing the IDisposable as an argument. To make the code accessible you'll want to put the IDisposableHelper class in one of your common assemblies.

// C#
public static class IDisposableHelper
{
  public static TResult Using<TResource, TResult> (TResource resource, Func<TResource, TResult> action)
    where TResource : IDisposable
  {
    using (resource) return action(resource);
  }

  public static void Using<TResource> (TResource resource, Action<TResource> action)
    where TResource : IDisposable
  {
    using (resource) action(resource);
  }  
}

Using the functions isn't quite as elegant as in F# but it definitely gets the job done in a much more functional manner.

Not returning a value

// C#
IDisposableHelper.Using(
  Image.FromFile(@"C:\Windows\Web\Screen\img100.png"),
  img => Console.WriteLine("Dimensions: {0} x {1}", img.Width, img.Height)
);

Returning a value

// C#
var dims =
  IDisposableHelper.Using(
    Image.FromFile(@"C:\Windows\Web\Screen\img100.png"),
    img => Tuple.Create(img.Width, img.Height)
  );

Console.WriteLine("Dimensions: {0} x {1}", dims.Item1, dims.Item2);

I'd still prefer to use F# but when I can't at least I can turn to this to make C# feel a little more like home.

About these ads

About Dave Fancher

Dave Fancher is a Software Engineer at Performance Assessment Network in Carmel, Indiana, a Microsoft MVP for Visual F#, and author of The Book of F# from No Starch Press. He has been building software with the .NET Framework since version 1.1. Dave is active within the Indiana software development community as a member of IndySA, a speaker at user groups throughout the state, and a two-time contributor to Indy GiveCamp. When not writing code he enjoys spending time with his family, watching movies, photography, and gaming on on his Xbox One.

Posted on March 23, 2013, in C#, F#, Languages, Software Development and tagged , , , . Bookmark the permalink. Comments Off.

Comments are closed.

Follow

Get every new post delivered to your Inbox.

Join 733 other followers

%d bloggers like this: