By Ramesh Balaji
Introduction Of the many new capabilities provided by .NET through its Common Language Runtime and .NET framework classes, “Delegates” or .NET Delegates is one worth examining. I am going to use VB.NET (BETA 2) to run through my examples.
This article covers the following aspects of Delegates.
a. Defining Delegates.
b. Using Delegates
c. Understanding how Delegate functions in the CLR Environment.
Of the many new capabilities provided by .NET through its Common Language Runtime and .NET framework classes, “Delegates” or .NET Delegates is one worth examining.
I am going to use VB.NET (BETA 2) to run through my examples.
Delegate is commonly defined as a Type Safe Pointer. To better understand a Type-Safe pointer, let’s see a how a callback function in C++/VC++ works. The Callback function is normally implemented in the Business tier of a 3-tier architecture (of course there are exceptions to that). Once the Business Logic component implements a particular functionality, say a complex arithmetic calculation, it informs a client that the job was performed successfully. In order to inform the client, it needs an address of the functionmethod implemented in the client. The address of a function is just a memory address; this address does not carry any information such as number of parameters, data type of each parameter and its return value. Since the Callback function does not have any idea of the Method Signature it is going to call, in short, it is not Type Safe.
However, Delegates provide the feature of Callback functions in a safe way. Taking the previous example, if the Business Logic finds that the function signature implemented by the Client differs in terms of number of parameters or parameter types or return values as opposed to the method signature, it is going to safely raise an error.
We can better understand through an example.
As a owner of a fictitious toy firm trying attract more local customers, I am going to offer special discounts of 10% on all toys to all local residents, whom I will identify by their phone numbers. If their area code is “479” (which is my area code), I am going to raise a message to the client saying “The Customer is eligible for 10% Discount”
This is a Normal Windows Form App written in VB.NET, which is going to accept the Customer First Name, Last Name and the Phone Number, which includes the area code and will perform the validation.
Step 1, I am going to define a Delegate called “MakeDelegate”. The code below is fundamental syntax for declaring a Delegate in VB.NET
Public Delegate Sub MakeDelegate (ByVal PhoneNo As String)
This Delegate class “MakeDelegate” is now capable of invoking a function, which can accept a Single String Parameter and will return VOID.
Being a Public type, it can be called anywhere inside my Application.
I am going to define a Customer Class, which has the following fields and a method.
Public Class Customer
Public FirstName As String
Public LastName As String
Public Sub ValidateCustomer (ByVal objDelegate As MakeDelegate, _
ByVal PhoneNo As String)
If PhoneNo.StartsWith (“479”) Then
The method ValidateCustomer is going to accept the PhoneNo and a Delegate Object of type “MakeDelegate” as the parameters and validate whether it is a local code or long-distance code and invoke the Delegate Object accordingly.
The Fields FirstName and LastName will store the customers’ first and last names.
In the third step, we are going to tell the Delegate object which Function/Procedure at the form class needs to be called when “ObjDelegate.Invoke(PhoneNo)” is called.
Dim objCustomer As Customer = New Customer()
Dim objDelegate As MakeDelegate
objDelegate = AddressOf NotifyClient
objCustomer.FirstName = txtFirstName.Text
objCustomer.LastName = txtLastName.Text
If we have a look at the above code, Customer Class instance is created and the reference variable for the “MakeDelegate” Delegate object is assigned.
Now examine the following line
objDelegate = AddressOf NotifyClient
We assign the local procedure “NotifyClient”, which is declared and defined inside the Windows Form Class to the Delegate Object.
Private Sub NotifyClient(ByVal PhoneNo As String)
MsgBox(“This Customer is Eligible for 10% Discount”)
Once we assign the instance of the Delegate, we must provide the address of a method implementation with a matching method signature.
If we carefully take a look at the NotifyClient, it also has a Single Parameter of data type String and it returns Void. The signature of “NotifyClient” procedure matches the signature of the Delegate “MakeDelegate”.
Assume that if MakeDelegate declaration looks like the declaration below
Public Delegate Sub MakeDelegate(ByVal PhoneNo As String, byval SomeValue as long)
then I am going to get a Compile time error. This is what we call Type Safe function pointers. If we look at the way .NET implements delegates, it always sees the matching signature starting with the function parameters, their data types, and the return values.
In a summary, If I run this program, the Customer class will be instantiated along with the delegate object “MakeDelegate”, the Address of local form class procedure NotifyClient is assigned to the Delegate class.
The ValidateCustomer Method of the Customer Class is called and it checks the PhoneNo. When it finds the phone number starts with “479”, it is going to call the Invoke method of the MakeDelegate object which will eventually call the “NotifyClient” function.
The implementation of Delegates is not really complicated because CLR and VB.NET compiler does a lot of things behind the scenes.
Let’s re-examine the following code
Public delegate MakeDelegate(phoneno)
When the VB.NET compiler sees the above line, it creates a public class “MakeDelegate” because it is declared as Public Delegate. If it would have been declared as Private, then it is going to create a Private class. This class will inherit from System.MultiCastDelegate. Which means all properties and methods of System.MulticastDelegate class will be inherited to the “MakeDelegate” Delegate Class
| | | .class public auto ansi sealed
| | | extends [mscorlib]System.MulticastDelegate
| | |___[MET] method .ctor : void(object,native int)
| | |___[MET] method BeginInvoke : class [mscorlib]System.IAsyncResult(string,class
| | |___[MET] method EndInvoke : void(string,class [mscorlib]System.IAsyncResult)
| | |___[MET] method Invoke : void(string)
I also pasted the ILDASM code above for further clarification.
When you take a look at the Delegate Constructor (bolded) in the ILDASM code, there are two parameters. The first parameter indicates the reference of the object being passed and the second parameter is the int32 value that identifies the Method. From our example, it should have “objCustomer” as the value for object reference parameter and “NotifyClient” as the value in the MethodInfo parameter.
The reference to object and method value is saved on the private fields respectively. In case you pass the Static Object, the object reference is set to NULL.
Now that we understand how the Delegate constructs objects, let’s see how the method is actually invoked.
I’ve pasted the line from ILDASM, that calls the invoke method of the Delegate Class.
|___[MET] method Invoke : void(string)
Look at it carefully. The compiler actually generates code to call the delegate object invoke method whenever it sees this line of code
This is how the .NET Delegate class works internally. However, it performs lots of things internally when it needs to invoke a chain of Delegate objects and during Asynchronous calls, but they are beyond the scope of this article.
In summary we now understand:
a. What is a Delegate and its purpose.
b. How to implement Delegates.
c. How a Delegate works
What I have given is just an introduction. If you would like to delve deeper into Delegate Classes, there are lot of useful articles you can find in http://msdn.microsoft.com (search for .NET Delegates). Happy reading!
About the Author
Ramesh Balaji develops business applications using ASP, VB and SQL Server. He’s a frequent contributor to the www.4guysfromrolla.com and www.asptoday.com. When not programming, he enjoys spending time with his kids. He can be reached at email@example.com.