Following my blog about Generic Delegates and Anonymous Methods, here is more:
Generics and anonymous methods can make code a lot more flexible.
Following I show different ways to accumulate the balance of Account objects. The Account class is a simple class that has a Balance property to access the balance of the class.
1. Summarizing the balance of Account objects in a collection can be done with the Accumulate method:
public static decimal Accumulate(IEnumerable e)
{
decimal sum = 0;
foreach (Account a in e)
{
sum += a.Balance;
}
return sum;
}
Invoking the method, the Account collection is passed:
decimal amount = Algorithm.Accumulate(accounts);
2. Making this method generic that it is possible to use other than Account objects, a generic method Accumulate can be implemented. However, because the Balance property is accessed for the accumulation, all generic TAccount classes must offer this property as is defined with the constraint IAccount.
public static decimal Accumulate<TAccount>(IEnumerable<TAccount> coll)
where TAccount : IAccount
{
decimal sum = 0;
foreach (TAccount obj in coll)
{
sum += obj.Balance;
}
return sum;
}
Invoking the method is not different to before:
decimal amount = Algorithm.Accumulate(accounts);
3. The second version has the requirement that all objects that are accumulated implement the Balance property. This can be more flexible by defining a generic delegate that defines the action.
Now the Accumulate mehtod can do anything to any object of a collection. What is done to the objects is defined with the delegate Action<>(). This Action delegate defines two parameters and a return type.
public delegate TSum Action<TObj, TSum>(TObj obj, TSum sum);
public static TSum Accumulate<TObj, TSum>(
IEnumerable<TObj> coll, Action<TObj, TSum> action)
{
TSum sum = default(TSum);
foreach (TObj obj in coll)
{
sum = action(obj, sum);
}
return sum;
}
To do the same as before - adding all balances - the implementation of the Action can be defined as anonymous method calling the Accumulate method.
decimal amount = Algorithm.Accumulate<Account, decimal>(
accounts,
delegate(Account a, decimal sum)
{
return a.Balance + sum;
});
This is really flexible as it is not only possible to use Account objects, but any object. Instead of accumulating some values anything else can be done, too.
Of course anonymous methods should only be used with very simple implementations that are not needed somewhere else. Instead of anonymous methods a normal method can be used, too.
Christian