Delegates are objects that you can use to call the methods of other objects. They are described as type-safe function pointers but, unlike in other languages, in VB.NET delegates are reference types based on System.Delegate.
Delegates can reference both functions and subroutines.
Delegates can reference both shared and instance methods.
Delegates can be useful in many scenarios; one is when you have a function that performs different tasks. Since a task can be performed in different ways, you can define a delegate parameter and the caller passes the function that he wants to execute as a parameter. One concrete example is sorting; you can sort a list based on different criteria; for instance, you can sort a list of clients by name, last purchase date, invoices amounts etc… If you write a function for each of those sorting scenarios, you can use delegates to pass it as a parameter to a function that executes it.
Let’s define a delegate for a function that accepts 2 integers and returns a long integer. Notice that when we define a delegate, we care much about its signature and return type. We have not mentioned what the actual mapping functions will actually do; in fact, this is why we create delegates; the above-mentioned delegate can be mapped to a function that sums 2 integers, subtracts 2 integers, multiplies 2 integers etc…
Delegate Function Del1 (ByVal x as integer, ByVal y as integer) As Long
Let’s now define 2 mapping functions:
Function AddIntegers (Byval a as integer, Byval b as integer) As Long
return a + b;
Function MultiplyIntegers (Byval a as integer, Byval b as integer) As Long
return a * b;
Now, let’s a write a function that makes use of Del1 as one of its parameters:
Function Process (f as Del1, x as integer, y as integer)
return f(x, y);
Dim i1 as integer = 5;
Dim i2 as integer = 6;
Dim r = Process(AddressOfAddIntegers, i1, i2); ‘r = 11
r = Process(AddressOfMultipleIntegers, i1, i2); ‘r = 30
N.B. As previously mentioned, delegates work with both instance and shared methods; however, the delegate itself is not instance nor shared and hence the keyword ‘shared’ cannot be used when defining a delegate; it’s the mapping function(s) that can be instance or shared; we can have 2 implementation functions for the same delegate, the first is shared and the second is instance.
1 – Corresponding parameters between the delegate and the implementations must be the same regarding byval and by ref.
2 – Corresponding types need not to be the same but they need to be convertible (i.e. widening or narrowing). If option strict is on, then widening is allowed only.
3 – If option strict is off, the return types must not be the same but must be convertible through widening or narrowing; if option strict is on, only widening is acceptable.
4 – If the delegate is a function, all implementations must be functions; if the delegate is a subroutine, implementations can be functions, subroutines or both.
Delegates and Lambda Expressions
We can use a lambda expression every time a delegate is expected. Consider the following delegate:
Delegate Sub Del1 (x as integer, y as integer)
Dim d1 As Del1 = Sub (a as integer, b as integer)
MsgBox(a + b);
Note that the lambda expression must be the same as the delegate; it is a subroutine if the delegate is a subroutine and it is a function if the delegate is a function.