WEBINAR:
On-Demand
Building the Right Environment to Support AI, Machine Learning and Deep Learning
Filtering with Delegates
Your goal now is to replace the
GetEvenNumbers method in
Listing 1 and
Listing 2 with a more generic method called
Select(). You can use a delegate as a parameter type. So declare a delegate named "Filter" for this purpose:
// In C#:
delegate bool Filter( int x );
' in VB:
Delegate Function Filter(ByVal x As Integer) _
As Boolean
The delegate takes an integer as a parameter and returns a Boolean value. The Boolean result allows you to implement filtering methods where the "x" will be included in the result if the return value of the filtering method is
true.
You can now implement the
Select() method, which takes a parameter of type Filter:
// In C#:
static List<int> Select( List<int> numbers,
Filter filter )
{
List<int> result = new List<int>();
foreach ( int i in numbers )
{
// call delegate
if ( filter( i ) == true )
{
result.Add( i );
}
}
return result;
}
' in VB:
Function [Select](ByVal numbers As _
List(Of Integer), _
ByVal filter As Filter) _
As List(Of Integer)
Dim result As New List(Of Integer)
For Each number In numbers
' call delegate
If filter(number) = True Then
result.Add(number)
End If
Next
Return result
End Function
The snippets show that the
Select method is able to perform a select operation without knowing what the selection criteria are. You've succeeded in making your
Select method generic and reusable in many scenarios.
It's worth noting that working with delegates in C# 3.0 and VB9 has been simplified. The snippets show that you can use the
filter variable as if it were an actual method. Previously you had to call the
Invoke(
) method on the delegate, in this case
filter.Invoke(i), in order to invoke the delegate.
Now that your reusable
Select method is in place, you can write methods that match the delegate and use them to filter your collection of integers:
// In C#:
static bool IsEvenNumber( int x )
{
return ( x % 2 == 0 );
}
static bool IsOddNumber( int x )
{
return ( x % 2 != 0 );
}
List<int> even = Select( _numbers, IsEvenNumber );
List<int> odd = Select( _numbers, IsOddNumber );
Print( even );
Print( odd );
' in VB:
Function IsEvenNumber(ByVal x As Integer) _
As Boolean
Return (x Mod 2 = 0)
End Function
Function IsOddNumber(ByVal x As Integer) _
As Boolean
Return (x Mod 2 <> 0)
End Function
Dim even = _
[Select](_numbers, AddressOf IsEvenNumber)
Dim odd = _
[Select](_numbers, AddressOf IsOddNumber)
Print(even)
Print(odd)
Both the
IsEvenNumber and
IsOddNumber match the Filter delegate and you can therefore use them when calling the
Select() method. The use of the delegate as a parameter type allows you to create a parameter that looks like it is a pointer or reference to a method; however, it is neither! The parameter is an object that inherits from System.Delegate. It is the C# compiler that does the magic of letting you pass in a method name as if it is a reference to the method. In C# 2.0, the syntax for calling
Select() is different; you need to create an instance of the delegate object like so:
List<int> even = Select(
_numbers, new Filter( IsEvenNumber ) );
Also notice how VB does not perform the same magic and requires you to use the
AddressOf keyword.