Working with Umbrella in .NET 3.5
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 :
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:
[code:c#]
Enumerable
.Range(20, 30)
.ForEach(
(index, value) => "Value #{0}={1}".InvariantCultureFormat(index, value)
);
[/code]
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 ?".
[code:c#]
var values = new List<int>(Enumerable.Range(1, 10));
values.Remove(v => v > 4);
[/code]
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.
The Action.ToDisposable() extension method
[code:c#]
var w = Stopwatch.StartNew();
for (int i = 0; i < 1000; i++) { }
Console.WriteLine(w.Elapsed);
[/code]
[code:c#]
class ProfileScope : IDisposable
{
Stopwatch w = Stopwatch.StartNew();
void IDisposable.Dispose()
{
Console.WriteLine(w.Elapsed);
}
}
[/code]
[code:c#]
using (new ProfileScope())
{
for (int i = 0; i < 1000; i++)
{
}
}
[/code]
[code:c#]
static IDisposable CreateProfileScope()
{
var w = Stopwatch.StartNew();
return Actions.Create(() => Console.WriteLine(w.Elapsed)).ToDisposable();
}
[/code]
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
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:
[code:c#]
using (MemoryStream stream = new MemoryStream())
{
int a = 0;
a.Serialization().Binary(stream);
// ...
}
[/code]
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.