Calling functions/Methods synchronously & asynchronously using Delegates
Being
a programmer, it’s almost daily routine to write such methods which
take plenty of processor cycles/time to perform some action. For
example some database operation/transactions, while using web services
or Remote Procedure Calling (RPC), File I/O operations, etc.
To
call such functions or methods which take plenty of time, user needs to
wait for process to complete and some time in exceptional cases
application hangs up if process couldn’t get complete for some reason.
But in both cases user gets annoy and User Interface (UI) gets freeze
until process completed if you have to call them synchronously.
In
synchronous way of communication, caller process/thread needs to wait
until called process/thread got complete but in case of asynchronous
caller just need to send request to perform operation and get back
means. It doesn’t need to wait for called process/thread completion.
Thanks to .Net team as they provide managed code Type-Safe mechanism to point any method or function and introduced Delegate.
Delegates are like Function Pointer in C/C++ but Type-Safe, flexible by
means of inheritance and powerful by means of referencing multiple
methods as well as powerful by means of asynchronicity and supporting
callback and calling them.
Delegate:
Delegate
is type-safe object which can point to any function to invoke them
synchronously and asynchronously. A single delegate has power to point
to multiple sub routines (such functions whose return type is VOID). It
invokes them at a time. Such delegates are known as Multicast delegate.
How to define Delegate:
A
delegate is quite easy to implement. Defining delegate is almost like
any function as following is definition of simple function in C#.
Return_Type Function_Name(Params); //Pseudo Code
int AddTwoNumbers(int Num1, int Num2); //C# Code
And to define delegate, we just need to add delegate keyword like below:
delegate Return_Type Function_Name(Params); //Pseudo Code
delegate int AddTwoNumbers(int Num1, int Num2); //C# Code
I hope it’s easier than Rocket Science. :P
Calling method synchronously Example:
Delegates can call methods in synchronously and asynchronously manners.
Invoke method uses to call target method synchronously for same Thread. "kwd">namespace
NSDelegate
{
"kwd">public class HeavyProcess
{
"kwd">public string GetWeatherInfo("kwd">int zip)
{
"cmt">
}
"kwd">public void MakeScriptOfDatabase()
{
"cmt">
}
}
"kwd">public class MyDelegateExample
{
"cmt">
"kwd">public delegate string dlgGetWeatherInfo("kwd">int zip);
HeavyProcess hp = "kwd">new HeavyProcess();
"kwd">public MyDelegateExample()
{
"cmt">
dlgGetWeatherInfo dlgWeatherInfo = "kwd">new dlgGetWeatherInfo(hp.GetWeatherInfo);
"cmt">
"kwd">string strWeatherInfo = dlgWeatherInfo.Invoke(54000);
}
}
}
Calling Method Asynchronously
BeginInvoke method used to call method asynchronously and EndInvoke methods have access on return value and input or output parameters. When we use BeginInvoke method
request, it goes to queue and handles return to caller thread for
proceed. Than/and target/called method would be run in another thread
from thread pool. These methods would run concurrently which seems as
both are running in parallel.
BeginInvoke method returns IAsyncResult which uses to pass as parameter whilst invoking EndInvoke method.
We can use two ways for determine to know that when to call EndInvoke method:
1). IAsyncResult object. We need to get WaitHandler and call WaitOne method to block execution until the WaitHandle get signal. "kwd">namespace
NSDelegate
{
"kwd">public class HeavyProcess
{
"kwd">public string GetWeatherInfo("kwd">int zip)
{
"cmt">
}
}
"kwd">public class MyDelegateExample
{
"cmt">
"kwd">public delegate string dlgGetWeatherInfo("kwd">int zip);
HeavyProcess hp = "kwd">new HeavyProcess();
"kwd">public MyDelegateExample()
{
"cmt">
dlgGetWeatherInfo dlgWeatherInfo = "kwd">new dlgGetWeatherInfo(hp.GetWeatherInfo);
"cmt">
IAsyncResult async = dlgWeatherInfo.BeginInvoke(54000, "kwd">null, "kwd">null);
"cmt">
async.AsyncWaitHandle.WaitOne();
"cmt">
"kwd">string strWeatherInfo = dlgWeatherInfo.EndInvoke(async);
}
}
}
2). Callback Delegate and Get Async State:
You
might be wondering about null parameters which I have passed in
BeginInvoke method in prior example code. Instead of first null
parameter which I have passed, we can pass reference of another method
which we want to be called automatically by the target method/thread
when target method completes execution. Ins’t it better than first
solution. Anyhow for that purpose we use AsyncCallback and give
reference of static Method which return type is void and (takes IAsync
object which return by BeginInvoke method.)
Second null parameter could be replaced by any object type data/value which used to represent state of method. "kwd">namespace
NSDelegate
{
"kwd">public class HeavyProcess
{
"kwd">public string GetWeatherInfo(
"kwd">int zip)
{
"cmt">
}
}
"kwd">public class MyDelegateExample
{
"cmt">
"kwd">public
delegate string dlgGetWeatherInfo(
"kwd">int zip);
HeavyProcess hp =
"kwd">new HeavyProcess();
"kwd">public MyDelegateExample()
{
"cmt">
dlgGetWeatherInfo dlgWeatherInfo =
"kwd">new dlgGetWeatherInfo(hp.GetWeatherInfo);
"cmt">
IAsyncResult async = dlgWeatherInfo.BeginInvoke(
54000,
"kwd">new AsyncCallback
(GetResultByCallback),
"st">
"Did you get message? :P");
}
"kwd">static void GetResultByCallback(IAsyncResult asyncResult)
{
"cmt">
System.Runtime.Remoting.Messaging.AsyncResult result =
(System.Runtime.Remoting.Messaging.AsyncResult) asyncResult;
"cmt">
dlgGetWeatherInfo dlg = (System.Runtime.Remoting.Messaging.AsyncResult)result.AsyncDelegate;
"cmt">
"kwd">string strWeatherInfo = result.EndInvoke(asyncResult);
"cmt">
"kwd">string strState = (
"kwd">string)result.AsyncState;
}
}
}
EndInvoke method must be called to complete delegates’ asynchronous call.
Multicast Delegate:
Power
of delegate is not over at calling single method synchronously or
asynchronously. Delegates can be used to call multiple methods as
delegate object can have reference of multiple methods but methods
return type should be void.
Internally Multicast delegates are a Link List of delegate objects and each node contains reference of prior delegate.
Delegates achieve this functionality by inheriting Multicast Delegate class
under System namespace. Multicast delegates can keep or point to
multiple handlers of different methods. It can be execute at single
call.
Calling multiple methods at once synchronously using Multicast delegate
Covariance and Contra variance Delegates "kwd">namespace
NSDelegate
{
"kwd">public class HeavyProcess
{
"kwd">public void MakeScriptOfDatabase()
{
"cmt">
}
"kwd">public void ETW()
{
"cmt">
}
}
"kwd">public class MyDelegateExample
{
"cmt">
"kwd">public delegate string dlgDBOperations();
HeavyProcess hp = "kwd">new HeavyProcess();
"kwd">public MyDelegateExample()
{
"cmt">
dlgDBOperations dlgWeatherInfo = "kwd">new dlgDBOperations(hp.MakeScriptOfDatabase);
"cmt">
dlgWeatherInfo += "kwd">new dlgDBOperations(hp.ETW);
"cmt">
dlgWeatherInfo();
"cmt">
dlgWeatherInfo += "kwd">new dlgDBOperations(hp.ETW);
"cmt">
dlgWeatherInfo();
}
}
}
First
of all, I would like to mention here one thing very important that
these features are supported from .net 2.0. Delegates are type of safe
function pointers but these are very flexible and are enough powerful
to support Inheritance, isn’t it cool! J
I
didn’t mean here that you can make derived delegates, $ actually they
support inheritance by means of return type and parameters type
subclasses of the method to whom delegate refer.
Covariance deals with return type of method whereas Contra variance deals with type of parameter(s).
Covariance example "kwd">namespace
NSDelegate
{
"cmt">
"kwd">public class Human { }
"cmt">
"kwd">public class Shemale : Human { }
"kwd">public class MyDelegateExample
{
"kwd">public delegate Human MyDelegates();
"kwd">static void Main()
{
"cmt">
MyDelegates delg1 = GetHuman;
"cmt">
MyDelegates delg2 = GetShemale;
}
"cmt">
"kwd">public static Human GetHuman()
{
"kwd">return new Human();
}
"cmt">
"kwd">public static Shemale GetShemale()
{
"kwd">return new Shemale();
}
}
}
Contravariance Example "kwd">namespace
NSDelegate
{
"cmt">
"kwd">public class Human { }
"cmt">
"kwd">public class Shemale : Human { }
"kwd">public class MyDelegateExample
{
"kwd">public delegate Human MyDelegates();
"kwd">static void Main()
{
"cmt">
MyDelegates delg1 = GetHuman;
"cmt">
MyDelegates delg2 = GetShemale;
}
"cmt">
"kwd">public void GetHuman(Human hum)
{
}
"cmt">
"kwd">public void GetShemale(Shemale shem)
{
}
}
}
Conclusion:
Delegate
is an object which can refer to method(s) and can call methods
synchornously and asynchrously (by running methods on another threads).
Using asynchornous delegates, we can call time taking processes of our
application like emailing, database transactions, calling web services,
File I/O operations. Also can run them on different threads which
doesn’t freeze UI and user doesn’t need to wait a lot.
Single Delegate can point to several methods of void return type and such kind of delegates are known as multicast delegates.
Delegates are enough flexible to support inheritence means which
can accommodate derived class of return type and parameter(s) type of
referenced method. These techniques are known as covariance and
contravariance which were introduced in .net 2.0.