"Delegates" are a means of indirectly calling a function or subroutine procedure through an object variable. You can define a Delegate object and then associate a particular function or subroutine procedure to it. The object can be passed between routines like any other object and finally the associated procedure can be called.
Delegates may be used to efficiently call a procedure from a table of procedures, based on a numeric index. They may also be used to pass a call-back procedure to a server process.
The Delegate statement creates a new named class that holds a template for the procedure to be called. For example, the statement
Delegate Function My_template(ByVal arg1 As Integer) As String
creates a class with the name My_template that can be used to call Function procedures that accept a single Integer argument by-value, and return a String value. This statement is only a declaration and does not do anything except create the My_template class.
Suppose you have two functions:
Public Function f0 (ByVal mode As Integer) As String
:
End Function
Public Function f1 (ByVal mode As Integer) As String
:
End Function
You can create an array of Delegate objects that refer to these functions, using the template defined earlier in the Delegate statement.
Dim del_obj(1) As My_template
del_obj(0) = New My_template(AddressOf f0)
del_obj(1) = New My_template(AddressOf f1)
or
del_obj(0) = New My_template("f0")
del_obj(1) = New My_template("f1")
The function type and arguments for the functions f0 and f1 must match the defining Delegate statement or a compiler error will be issued for by the New statements above.
If you have an index variable whose value is either 0 or 1, it can be used to select which of the two functions is executed.
str = del_obj(index)(3) ' Call f0 or f1 with mode = 3
The Delegate statement creates a new class that serves as a template for any Delegate objects that are associated with it. The Delegate statement’s procedure type (Sub or Function), the procedure argument list, and the Function result type must match any procedures that are later associated with a Delegate object of this class. You need to have a separate Delegate statement for each variation of procedure type and argument list. A Delegate statement is similar to creating a new class with the name of the Delegate. You cannot create a Delegate class for a property method.
For example, the statement
Delegate Function My_template(ByVal arg1 As Integer) As String
creates a class with the name My_template that can be used to call Function procedures that accept a single Integer argument by-value, and return a String value.
Like other objects, a Delegate object must be declared before it can be used. Objects of this type are just like any other object and can be global, inside a class, or local in a procedure. A typical object variable declaration is:
Dim del_obj As My_template
which creates an object variable del_obj that is an instance of the previously declared Delegate named My_template. Before the object variable can be used, the actual object must be created with a New procedure using the name of the procedure as a String, or using the AddressOf operator. For example:
del_obj = New My_template("f0")
or
del_obj = New My_template(AddressOf f0)
The parameter list and procedure type of f0 must match the template of the Delegate statement for My_template.
To associate a Delegate object with a non-shared class procedure, you need to provide both the procedure name and the object instance to the AddressOf operator. You cannot use a String in this case. The Delegate object saves a pointer to the object instance along with the procedure. For example:
Class My_class
:
Public Function My_fn(ByVal mode As Integer) As String
:
End Function
End Class
Public Sub Test
Dim my_obj As New My_class ' Create an object from My_class
Dim del_obj As My_template
del_obj = New My_template(AddressOf my_obj.My_fn)
' At this point, del_obj refers to my_obj.My_fn
Console.Writeline(del_obj(3)) ' Call my_obj.My_fn(3)
End Sub
The AddressOf operator may be used in the constructor (New clause) when creating Delegate objects. This operator finds the address of a procedure. If the procedure is a non-shared class procedure, it also determines the object to be associated with the call. For example:
del_obj = New My_template(AddressOf global_function)
Associates del_obj with a global function that does not depend on any object.
del_obj = New My_template(AddressOf my_object.class_function)
Associates del_obj with the object referenced by my_object and the class member function class_function. If del_obj is used later to invoke class_function, that function is called with the value of my_object at the time that del_obj was instantiated.
When the AddressOf operator is used in a New clause, the compiler finds the name of the procedure during compilation. When a String containing the procedure name is used in a New clause, the procedure name must be found during execution of the procedure. So AddressOf is more efficient, but the String argument is more flexible since a String variable can be used to associate different procedures with the same Delegate object.
When a New clause contains a String variable, the procedure name must either be a module-level public procedure, or a top-level class public shared procedure. The String variable must have one of the following forms: