Generic Delegates C# Help

delegates are type-safe references to methods. With generic delegates, the parameters of the delegate can be defined later.

The .NET Framework defines a generic EventHandler delegate with the second parameter of type TEventArgs, so it is no longer necessary to define a new delegate with every new parameter type:

public sealed delegate void EventHandler<TEventArgs>(object sender,
TEventArgs e)
where TEventArgs : EventArgs

Implementing Methods Called by Delegates

The method Accumulate () is changed to have two generic types. Tlnput 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:

Img

The method Accumulate () can be invoked using an anonymous method that specifies that the balance of the account should be added to the second parameter that is of type Action:

Img

Instead of using anonymous methods, you can use a Lambda expression to pass it to the second parameter:

img

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

static decimal AccountAdder(Account a, decimal d}
{
retu~ a.Balance + d;

}

And use the address of the AccountAdder method with the Accumulate method:

decimal amount = Algorithm. 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:

Img

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 2,000 are accumulated as defined by the second Lambda expression a => a. Balance> 2000:

decimal amount = AIgorithm.Accumulatelf<Account. decimal> (
accounts. (a. d) => a.Balance + d. a => a.Balance > 2000);

Using Generic Delegates with the Array Class

That demonstrated different sort techniques with the Array class by using the IComparable and IComparer interfaces. Starting with .NET 2.0, some methods of the Array class use generic delegate types as parameters. The following table shows these methods, the generic type, and the functionality.

Img

Let’s get into how these methods can be used.

The Sort () method accepts this delegate as parameter:

public delegate int Comparison<T>(T x, T y);

This way it is possible to sort the array by using a Lambda expression passing two Person objects. With an array of Person objects, parameter T is of type Person:

The Array. ForEach () method accepts an Action<T> delegate as parameter to invoke the action for every element of the array:

public delegate vbid Action<T>(T obj);

This way, you can write every person to the console by passing the address of the method Console. WriteLine. One overload of theWriteLine () method accepts the Object class as parameter type. Because Person derives from Object, this fits with a Person array:

Array. ForEach (persons, Console.WriteLine);

The result of the ForEach () statement writes every person of the collection referenced by the persons variable to the console:

Emerson Fittipaldi
Niki Lauda
Ayrton Senna
Michael Schumacher

If more control is needed, you can pass a Lambda expression that fits the parameter defined by the delegate:

Array. ForEach (persons, p => Console.WriteLine(‘{O}’, p.LastName);

Here, the result is the last name written to the console:

Fittipaldi
Lauda
Senna
Schumacher

The Array. FindAll () method r~quires the Predicate<T> delegate:

public delegate bool Predicate<T>(T match);

The Array. FindAll () method invokes the predicate for every element in the array and returns a new array where the predicate returns true for the element. In the example, true is returned for all Person objects where the LastName starts with the string “S”:

Person[] sPersons = Array. FindAll (persons, p => p.LastName.StartsWith(‘S’);

Iterating through the returned collection sPersons to write it to the console gives .this result:

Ayrton Senna
Michael Schumacher

The Array. convertAll () method used the generic delegate Converter with two generic types. The first generic type Tlnput is the input parameter, the second generic type TOutput is the return type:

public delegate’TOutput Converter<Tlnput, TOutput>(Tlnput input);

The ConvertAll () method is very useful if an array of one type should be converted to an array of another type. Following is a Racer class that is unrelated to the Person class. The Person class contains the FirstName and LastName properties, while the Racer class defines for the name of the racer just one property Name:

Using Array. Convert All () you can easily convert the person array persons to a Racer array. The delegate is invoked for every Person element. In the anonymous method implementation for every person, a new Racer object is created, and the FirstName and LastName are passed concatenated to the constructor, which accepts a string. The result is an array of Racer objects:

Racer() racers =
Array.ConvertAll<Person, Racer> (
persons,
p => new Racer(String.Format(‘{O) {l)’, p.FirstName, p.LastName)’;

Posted on October 29, 2015 in Generics

Share the Story

Back to Top
Share This