What Is Delegates In .Net ?
A delegate can be defined as a type safe function pointer. You use delegates to call the methods of other objects. They are object-oriented function pointers since they allow a function to be invoked indirectly by using a reference to the function. It wraps up the memory address of a function in your code. The system makes use of delegate whenever you create or use an event in code. When an event is called, the framework examines the delegate behind the event and then calls the function that the delegate points to.
However, unlike function pointers, the delegates in .NET are reference types, based on the class System.Delegate. In addition, delegates in .net can reference both shared and instance methods.
Using Delegates
You can declare a Delegate object and then instantiate it. You can then call the delegate. The following example shows how a Delegate object is declared, instantiated and called.
Public Class myownclass
Inherits System.Windows.Forms.Form
'decalring a delegate object
Delegate Sub mydelegate()
Dim delegateobject As mydelegate
Public Sub msgeven()
MsgBox("You have entered an even number")
End Sub
Public Sub msgodd()
MsgBox("You have entered an odd number")
End Sub
Public Sub CallsOneSub(ByVal number As Integer)
Dim result As Integer
result = number Mod 2
If result = 0 Then
delegateobject = New mydelegate(AddressOf msgeven)
Else
delegateobject = New mydelegate(AddressOf msgodd)
End If
delegateobject()
End Sub
In the above code, a Delegate type called mydelegate is declared. An object of Delegate type is declared as delegateobject. Two procedures msgeven(), msgodd() are written. In the procedure CallsOneSub(), depending on the value of the argument, delegateobject is instantiated either for msgeven() or msgodd(). The call to delegateobject() will result in the call to the appropriate method.
Why do we have delegates
Delegates are there for the same reason as we had interfaces in VB6. They ensure that whatever funtion is reference, it will have the signature we require, meaning that we can know at design time what parameters we can pass, although we don't know to what function we will be passing them eventually.
Take multithreading for instance, we need to pass a delegate for ThreadStart, which is a procedure that doesn't take any parameters. Because we need to pass a delegate, it needs to be a procedure with no parameters, the name doesn't matter. Passing any other procedure (with parameters) will result in error.
Delegates & AddressOf Operator
Delegates are used when there is a need for an intermediary between a calling procedure and the procedure being called. The need for an intermediary arises in situations when an object that raises an event should be able to call diffrenet handlers under different circumstances. As the object that raises events cannot know before hand which event handler is handling a specific event, there is a need for an intermediary that can dynamically associate event handlers with events. In .NET, a delegate is used as the intermediary when the AddHandler attaement is used. At runtime, the delegate automatically forwards event calls to the appropriate event handlers.
The AddressOf operator implicitly creates an instance of a delegate. Assume that you create a button called cmdsave and write two event handlers for the click event of the button, cmdsave_click1 and cmd_click2. You can add radio buttons to the form that has the button and decide on the event handler to be called depending on the button selected. To do so, you will write the following code in the form class:
Private Sub cmdsave_Click1(ByVal sender As System.Object, ByVal e As System.EventArgs)
MsgBox("Message from Click1")
End Sub
Private Sub cmdsave_Click2(ByVal sender As System.Object, ByVal e As System.EventArgs)
MsgBox("Message from Click2")
End Sub
Private Sub RadioButton1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButton1.CheckedChanged
RemHandler() 'calling the remove handler function
AddHandler cmdsave.Click, AddressOf Me.cmdsave_Click1
End Sub
Private Sub RadioButton2_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButton2.CheckedChanged
RemHandler() 'calling the remove handler function
AddHandler cmdsave.Click, AddressOf Me.cmdsave_Click2
End Sub
Public Sub RemHandler()
RemoveHandler cmdsave.Click, AddressOf Me.cmdsave_Click1
RemoveHandler cmdsave.Click, AddressOf Me.cmdsave_Click2
End Sub
In the above code, two event handlers cmdsave_click1 and cmd_click2, are defined for the click event of a button named cmdsave. Two radio buttons named RadioButton1 and RadioButton2 are added. On selecting RadioButton1, AddHandler is used to associate cmdsave_click1 with ths click event of the button. On selecting RadioButton2, AddHandler is used to associate cmdsave_click2 with the click event of the button. When you click the button, a message box is displayed depending on the radio button selected. In the above code there is no mention of a delegate object because a delegate object is returned implicitly. In addition, assuming you select RadioButton1 first and then select RadioButton2, then both the event handlers will be called. This happens because both the event handlers get added to the list of event handlers for the click event of the button. You can remove event handlers dynamically by using the RemoveHandler keyword.
How do Delegates actually work internally
The implementation of Delegates is not really complicated because CLR and VB.NET compiler does a lot of things behind the scenes.
Public delegate mydelegate(argument1)
When the .NET compiler sees the above line, it creates a public class myDelegate because it is declared as Public Delegate. It would have created a private class if the delegate was declared private. This class will inherit from System.MultiCastDelegate. All properties and methods of System.MulticastDelegate class will be inherited to the mydelegate Delegate Class
__[CLS] mydelegate
| | | .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
[mscorlib]System.AsyncCallback,object)
| | |___[MET] method EndInvoke : void(string,class [mscorlib]System.IAsyncResult)
| | |___[MET] method Invoke : void(string)
| |
The below line from ILDASM calls the invoke method of the delegate class:
|___[MET] method Invoke : void(string)
The compiler generates code to call the delegate object invoke method when it sees
objDelegate.Invoke(PhoneNo)
Multicasting
There can be cases where you would want to call more than one method through one delegate. This is known as multicasting. To do this we make use of Delegate. Combine shared method. The Combine method takes an array of delegates as a parameter and returns a new delegate. This new delegate represents the combination of all the delegates in that array.
To see how this works, in the following code, I'll create a simplistic class that declares a delegate:
Public Class MyDelegate
' the delegate declaration
Public Delegate Sub StrDelegate(ByVal s As String)
End Class
Public Class MynewClass
Public Shared Sub WriteStr(ByVal str As String)
Console.WriteLine(".......Writing string {0}........", Str)
End Sub
Public Shared Sub LogStr(ByVal s As String)
Console.WriteLine("........Logging string {0}......", Str)
End Sub
Public Shared Sub TransmitStr(ByVal str As String)
Console.WriteLine("........Transmitting string {0}........", Str)
End Sub
End Class
Instantiate three StrDelegate objects in the Run method of the MynewClass as follows:
Dim Writer, Logger, Transmitter As MyClassWithDelegate.StringDelegate
The instantiate these delegates by passing in the address of the methods that you have to wrap as follows:
myWriter = New MynewDelegate.StrDelegate( _AddressOf MynewClass.WriteStr)
myLogger = New MynewDelegate.StrDelegate( _AddressOf MynewClass.LogStr)
myTransmitter = New MynewDelegate.StrDelegate(_AddressOf MynewClass.TransmitStr)
Now we will instantiate a multicast delegate. This is what will be used to combine the other three delegates:
Dim myMulticastDelegate As MyDelegate.StrDelegate
Make an array of the two delegates:
Dim myarr() As MyDelegate.StrDelegate = {myWriter, myLogger}
Now use this array to instantiate the multicast delegate:
mymulticastDelegate = _ DirectCast(System.Delegate.Combine(myarr), _
MyDelegate.StrDelegate)
You can add the third delegate as follows:
myMulticastDelegate = _
DirectCast(System.Delegate.Combine(myMulticastDelegate, myTransmitter), _
MyDelegate.StrDelegate)
You can remove a delegate form the collection as follows:
myMulticastDelegate = _
DirectCast(System.Delegate.Remove(myMulticastDelegate, myLogger), _
MyDelegate.StrDelegate)
Difference Between Delegates and Interfaces
You use delegates when you think of a .NET code that takes callback parameters, which look a lot like strongly typed method pointers in C++. You may not think that you can implement a callback parameter as an interface. Interfaces and delegates have a common key property of allowing you to call a method with the right prototype without knowing which object implements the method, which instance is bound to the call, or the name of the method you're calling.
1. Interface calls are faster than delegate calls. An interface reference is a reference to an instance of an object which implements the interface. An interface call is not that different from an ordinary virtual call to a method. A delegate reference, on the other hand, is a reference to a list of method pointers. While invoking a delegate looks like you're making an indirect call through a method pointer, it's actually a subroutine call that walks the list of method pointers. The overhead involved in making the call and walking the list means that delegate invocation can be two or three times slower than calling a method through an interface reference.
2. Interfaces are also a bit more general than are delegates. A single interface reference gives you access to all the methods of the interface. You can also check if the interface is implemented by this object type, or if the object also implements that other interface. If it does, you can cast the interface reference to an instance reference, or to a reference to another interface. Conversely, you can not go from a delegate to the instances it will call or to any other methods those instances may support.
However, don't conclude from this that you should always implement callbacks via interfaces, not delegates. One key difference between delegates and interfaces is that you can create a delegate to any method with the right prototype.
No comments:
Post a Comment