Working with Umbrella in .NET 3.5

By Jay at November 08, 2008 16:06 Tags: ,
If you've been using .NET 3.5, and the new features that are provided by C# 3.0, and especially LINQ, you must have wondered why, oh why, there isn't an extension named ForEach on an IEnumerable<T>.

Well, I still haven't figured that out, though it appears that it might have something to do with the fact that by nature an Action<T> is most of the time not "pure", which means that it modifies some states, somewhere. I can't remember where I've found that explanation, though it "might" make sense from a functional point of view.

But you may wonder why, then, is there a ForEach method on List<T> ? Well, I don't know why there is that kind of consistency issue, but I know there is one library that somehow tries to fix this :
 
 
This library fills the gaps left by the BCL, and adds a whole bunch of new extension methods that eases the use of .NET 3.5 classes. This library is not a framework though, mainly because you don't need to redesign your whole application to use it.

A few weeks ago during a presentation of Umbrella at the .NET User Group of Montreal, the creators Francois Tanguay and Erik Renaud from nVentive, were asked the question "Where do we start ?". This is a tough question to answer, because of the nature of umbrella, which "plugs" itself everywhere it can.

Using Umbrella

Let’s see a simple example:

    Enumerable
        .Range(20, 30)
        .ForEach(
            (index, value) => "Value #{0}={1}".InvariantCultureFormat(index, value)
        );

As you can see, using Umbrella requires most of the time the use of lambda expressions. Here, this example is an answer to the question "How can I get the index of the enumerated value in a foreach statement ?".

Another extension provided by Umbrella is the Remove method on an ICollection by specifying a predicated to select elements to be removed.

            var values = new List<int>(Enumerable.Range(1, 10));
            values.Remove(v => v > 4);

Sure, you can write some code that does this, but you'll have to create a temporary list to store elements to be removed, then remove them from the collection.

There is also an extension on IDictionary<> that simplifies the use of TryGetValue which requires an “out” argument, which is particularly annoying to write. Umbrella provides a TryGetValueOrDefault that either gives you the value for the key you requested, or default(TValue) if the key is not found.
 

The Action.ToDisposable() extension method

One particularly interesting extension is the ability to encapsulate an Action delegate into an anonymous disposable instance. Let’s say that we need to profile the duration of a particular scope of code. We would need to write something like this :


    var w = Stopwatch.StartNew();
    for (int i = 0; i < 1000; i++)  { }
    Console.WriteLine(w.Elapsed);



We would have to write the enclosing code to time for each portion of code we would need to profile. You could of course write a class that would do this on purpose :


    class ProfileScope : IDisposable
    {
        Stopwatch w = Stopwatch.StartNew();
        void IDisposable.Dispose()
        {
            Console.WriteLine(w.Elapsed);
        }
    }


And it’s being used like with a “using” statement :


    using (new ProfileScope())
    {
        for (int i = 0; i < 1000; i++)
        {
        }
    }

This time, timing a block of code is somehow easier to write, however, there is a way to simplify the writing of the writing of the utility class by doing this:

    static IDisposable CreateProfileScope()
    {
        var w = Stopwatch.StartNew();
        return Actions.Create(() => Console.WriteLine(w.Elapsed)).ToDisposable();
    }

We can use here the ToDisposable extension to be able to call the specified action in the dispose method of some disposable class.

The point of this code is to avoid exposing the inner details of the profiling code, and just expose a known and generic way for executing something at the end of a scope.

Extension Points

There is one drawback when using extension methods: They tend to “pollute” the original type. By pollute I mean that they appear in the IntelliSense window. Because it is easy to add extension methods, you end up having hundreds of new methods on a type, which make IntelliSense much less useable.

The Umbrella guys came up with the idea of Extension Points, which are a way to group extension methods the namespaces do for types.

This is somehow a hack from a code perspective, but is rather ingenious from a usability perspective. For instance, extending the serialization applies to every type that exists, and placing all serialization extension methods directly on System.Object is not a good idea.

Extensions points are used like this:

    using (MemoryStream stream = new MemoryStream())
    {
        int a = 0;
        a.Serialization().Binary(stream);
        // ...
    }



Serialization is an extension method placed on every object that returns an SerializationExtensionPoint instance, and the “Binary” method extends that type instead of System.Object.

It is important to remember that Umbrella is for most of its code is not "rocket science", as it probably contains code that you may already have partially developed for your own project. It's only the amount of small but useful utility methods that Umbrella provides that makes it worth using.

I’ll be writing a few other posts about Umbrella; there are a lot of extensions in there that are great time savers.

 

blog comments powered by Disqus

About me

My name is Jerome Laban, I am a Software Architect, C# MVP and .NET enthustiast from Montréal, QC. You will find my blog on this site, where I'm adding my thoughts on current events, or the things I'm working on, such as the Remote Control for Windows Phone.