Generic Delegates


As discussed in Chapter 6, "Events and Delegates," delegates are type-safe references to methods. With generic delegates, the parameters of the delegate can be defined later.

The method Accumulate() is changed to have two generic types. TInput is the type of the objects that are accumulated and TSummary is the returned type. The first parameter of Accumulate is the interface IEnumerable<T>, as it was before. The second parameter requires the Action delegate to reference a method that is invoked to accumulate all balances.

With the implementation, the method referenced by the Action delegate is now invoked for every element, and then the sum of the calculation is returned:

 public delegate TSummary Action<TInput, TSummary>(TInput t, TSummary u); public static TSummary Accumulate<TInput, TOutput>(IEnumerable<T> coll,  Action<TInput, TSummary> action) { TSummary sum = default(TSummary); foreach (TInput input in coll) { sum = action(input, sum); } return sum; } 

The method Accumulate can be invoked using an anonymous method that defines that the balance of the account should be added to the second parameter:

 decimal amount = Accumulate<Account, decimal>( accounts, delegate(Account a, decimal d) { return a.Balance + d; }); 

If the addition of Account balances is needed more than once, it is useful to move the functionality into a separate method, AccountAdder():

 static decimal AccountAdder(Account a, decimal d) { return a.Balance + d; } 

And use the AccountAdder method with the Accumulate method:

 decimal amount = Accumulate<Account, decimal>( accounts, AccountAdder); 

The method referenced by the Action delegate can implement any logic; for example, a multiplication could be done instead of a summation.

The Accumulate() method is made more flexible with the AccumulateIf() method. With AccumulateIf(), an additional parameter of type Predicate<T> is used. The delegate Predicate<T> references the method that will be invoked to check whether the account should be part of the accumulation. In the foreach statement, the action method will be invoked only if the predicate match returns true:

 public static TSummary AccumulateIf<TInput, TSummary>( IEnumerable<TInput> coll, Action<TInput, TSummary> action, Predicate<TInput> match) {    TSummary sum = default(TSummary);    foreach (TInput a in coll)    { if (match(a)) { sum = action(a, sum); }    }    return sum; } 

Calling the method AccumulateIf() can have an implementation for the accumulation and an implementation for the predicate. Here, only the accounts with a balance higher than 2000 are accumulated:

 decimal amount = Algorithm.AccumulateIf<Account, decimal>( accounts,  delegate(Account a, decimal d) { return a.Balance + d; }, delegate(Account a) {return a.Balance > 2000 ? true : false; }); 




Professional C# 2005
Pro Visual C++ 2005 for C# Developers
ISBN: 1590596080
EAN: 2147483647
Year: 2005
Pages: 351
Authors: Dean C. Wills

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net