Saturday, July 15, 2017

Delegates in C# - I



What is Delegate?

In C#, a delegate defines a Type. But it is special type of Type that references methods.

A delegate is a type safe function pointer i.e. it holds a reference(pointer) to a function having the same signature.
In other words, a delegate is just the memory address of a method that matches the same signature as the delegate.
Specifically, a delegate maintains three important pieces of information
The address of the method on which it makes calls
The parameters (if any) of this method
The return type (if any) of this method

A delegate is a reference type variable that holds the reference to a method. The reference can be changed at runtime.
All delegates are implicitly derived from the System.Delegate Class.
Syntax:
Delegate <return type> <delegate-name> <Parameter list>
The signature of the delegate must match the signature of the function the delegate points to, otherwise we will get a compile time error. Therefore, the delegates are called as type safe function pointers.
A delegate is similar to a class. We can create an instance of it, and when we do so, we pass in the function name as a parameter to the delegate constructor, and it is to this function the delegate will point to.

The syntax of delegate looks very much similar to a method with a delegate keyword.
A delegate is reference type that basically encapsulates the reference of methods. It is a similar to class that store the reference of methods which have same signature as delegate has.

It is very similar to a function pointer in C++, but delegate is type safe, object oriented and secure as compare to C++ function pointer.

We could use delegates to create a queue of methods that need to be called in order. Delegates have built-in support for asynchronous operations that run on a different thread for better performance. Most importantly, delegates allow us to create events.

An event handler signature, i.e. the return type and the number and types of arguments it takes, is determined by the signature of the delegate used to define the event.

A delegate instance literally acts as a delegate for the caller: the caller invokes the delegate, and then the delegate calls the target method. This indirection decouples the caller from the target method.

Assigning a method to a delegate variable creates a delegate instance: eg below
delegate int Transformer (int x);
static int Square (int x) { return x * x; }
Transformer t = Square;

Event handlers are connected to a control’s events via special objects called delegates.

Type compatibility
Delegate types are all incompatible with one another, even if their signatures are the same:
delegate void D1();
delegate void D2();
D1 d1 = Method1;
D2 d2 = d1; // Compile-time error

The following, however, is permitted:
D2 d2 = new D2 (d1);

Delegate instances are considered equal if they have the same method targets:
delegate void D();
...
D d1 = Method1;
D d2 = Method1;
Console.WriteLine (d1 == d2); // True
Multicast delegates are considered equal if they reference the same methods in the same order.


Covariance and Contravariance (ie.SubClass & BaseClass)
Covariance and contravariance give you some flexibility when assigning methods to delegate variables. They basically let you treat the return type and parameters of a delegate polymorphically.
Covariance lets a method return a value from a subclass of the result expected by a delegate. For example, suppose the Employee class is derived from the Person class and the ReturnPersonDelegate type represents methods that return a Person object. Then you could set a ReturnPersonDelegate variable equal to a method that returns an Employee because Employee is a subclass of Person. This makes sense because the method should return a Person, and an Employee is a kind of Person. (A variable is called covariant if it enables covariance.)

Contravariance lets a method take parameters that are from a superclass of the type expected by a delegate. For example, suppose the EmployeeParameterDelegate type represents methods that take an Employee object as a parameter. Then you could set an EmployeeParameterDelegate variable equal to a method that takes a Person as a parameter because Person is a superclass of Employee. When you invoke the delegate variable’s method, you will pass it an Employee (because the delegate requires that the method take an Employee parameter) and an Employee is a kind of Person, so the method can handle it. (A variable is called contravariant if it enables contravariance.)



When you call a method, you can supply arguments that have more specific types than the parameters of that method. This is ordinary polymorphic behavior. For exactly the same reason, a delegate can have more specific parameter types than its method target. 
This is called contravariance.
Here’s an example:
delegate void StringAction (string s);
class Test
{
static void Main()
{
StringAction sa = new StringAction (ActOnObject);
sa ("hello");
}
static void ActOnObject (object o) => Console.WriteLine (o); // hello
}


If you call a method, you may get back a type that is more specific than what you asked for. This is ordinary polymorphic behavior. For exactly the same reason, a delegate’s target method may return a more specific type than described by the delegate.
This is called covariance. For example:
delegate object ObjectRetriever();
class Test
{
static void Main()
{
ObjectRetriever o = new ObjectRetriever (RetrieveString);
object result = o();
Console.WriteLine (result); // hello
}
static string RetrieveString() => "hello";
}
ObjectRetriever expects to get back an object, but an object subclass will also do:
delegate return types are covariant.


Generic delegate type parameter variance
we saw how generic interfaces support covariant and contravariant type parameters. The same capability exists for delegates too (from C# 4.0 onward).

If you’re defining a generic delegate type, it’s good practice to:
• Mark a type parameter used only on the return value as covariant (out).
• Mark any type parameters used only on parameters as contravariant (in).
Doing so allows conversions to work naturally by respecting inheritance relationships between types.


The following delegate (defined in the System namespace) has a covariant TResult:
delegate TResult Func<out TResult>();
allowing:
Func<string> x = ...;
Func<object> y = x;
The following delegate (defined in the System namespace) has a contravariant T:
delegate void Action<in T> (T arg);
allowing:
Action<object> x = ...;
Action<string> y = x;


The .NET Framework defines two generic delegate types that you can use to avoid defining your own delegates in many cases:
1. Action and
2. Func.

The generic Action delegate represents a method that returns void. Different versions of Action take between 0 and 18 input parameters. The following code shows the definition of the Action delegate that takes two parameters: public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2) The keyword in within the generic parameter list indicates that the T1 and T2 type parameters are contravariant.

The following code shows two ways you could declare variables of that type:
// Method 1.
  private delegate void EmployeeParameterDelegate(Employee employee);
  private EmployeeParameterDelegate EmployeeParameterMethod1;

// Method 2. private Action<Employee> EmployeeParameterMethod2;


Func Delegates
The generic Func delegate represents a method that returns a value. As is the case with Action, different versions of Func take between 0 and 18 input parameters.
The following code shows the definition of the Func delegate that takes two parameters:

public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2)

The three types defined by the generic delegate represent the types of the two parameters and the return value.
The code in the previous section defined a ReturnPersonDelegate type that takes no parameters and returns a Person object.
The following code shows two ways you could declare variables of that type:
 // Method 1.
  private delegate Person ReturnPersonDelegate();
 private ReturnPersonDelegate ReturnPersonMethod1;

// Method 2. private Func<Person> ReturnPersonMethod2;

This code’s first statement defines the ReturnPersonDelegate type. The statement after the first comment declares a variable of that type. The statement after the second comment declares a com-parable variable of type Func<Person>.

Why do we use Delegate?
There are following reason because of we use delegate.
  1. It is used for type safety.
  2. For executing multiple methods through one execution.
  3. It allows us to pass methods as parameter to another function
  4. For asynchronous programming.
  5. For Call back method implementation.
  6. It is also used when working with event based programming.
  7. When creating anonymous method.
  8. When working with lambda expression.
  9. They are used for plug-in our logic without having to modifying the original class or method logic. i.e. we can decouple the logic with the help of delegates.

When Do You Use Delegates?

I believe that a lot of people can answer the "what is a delegate?" question in interviews, but are not able to explain when to use it. No worries! Let me tell you a few important points about delegates.
  1. These are used to represent or refer to one or more functions.
  2. These can only be used to define call-back methods.
  3. In order to consume a delegate, we need to create an object to delegate.
  4. Delegates are especially used for implementing events and the call-back methods.


How many types of Delegate in C#?
There are three types of delegates available in C#.
  1. Simple/Single Delegate:
A single delegate instance can reference more than one target method. A target method can be added to delegate instance using += and removed using -=. The target methods are always called in the order they were added to the delegate instance.
  1. Multicast Delegate
  2. Generic Delegate
What are the ways to create and use delegate?
There are only five steps to create and use a delegate and these are as following.
  1. Declare a delegate type.
  2. Create or find a method which has same type of signature.
  3. Create object/instance of delegate
  4. Pass the reference of method with delegate instance.
  5. At last Invoke the delegate object.   
There are different ways to create delegate in C#.

  1. Action
  2. Func
  3. Predicate
   What is Single Delegate?
When Delegate takes reference with single method only then it is called Single Delegate. It is used for invocation of only one reference method. 
Following example has a delegate name as "TestDelegate" with one parameter as string.
using System;
namespace EventAndDelegateExamples
{
    delegate void TestDelegate(string name);
    class FunctionPointerExample
    {
        public void GetName(string name)
        {
            Console.WriteLine("Full Name is : " + name);
        }       
    }
}
Below code snippet that first we are creating a instance of TestDelegate and passing the reference of method "objFunctionPointerExample.GetName" method with objDelegate1.
FunctionPointerExample objFunctionPointerExample = new FunctionPointerExample();
 
//Call GetName function using TestDelegate
TestDelegate objDelegate1 = new TestDelegate(objFunctionPointerExample.GetName);
objDelegate1.Invoke("Mukesh Kumar");
To invoke the delegate, just need to use Invoke method to pass required parameter.

What is Multicast Delegate?
When Delegate takes reference with multiple methods then it is called multicast delegate. It is used for invocation of multiple reference methods. We can add or remove references of multiple methods with same instance of delegate using (+) or (-) sign respectively. It need to consider here that all methods will be invoked in one process and that will be in sequence.
Following example has a delegate name as "TestMultiCastDelegate" with one parameter as int.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace EventAndDelegateExamples
{
    delegate void TestMultiCastDelegate(int a);
    class MultiCastDelegateExample
    {
        internal void GetSalary(int AnnualSalary)
        {
            Console.WriteLine("Monthly Salary is "+ AnnualSalary / 12);
        }
 
        internal void GetSalaryAfterDeduction(int AnnualSalary)
        {
            if (AnnualSalary > 12000)
            {
                Console.WriteLine("Monthly Salry after deduction is "+ ((AnnualSalary / 12) - 500));
            }
            else
            {
                Console.WriteLine("Monthly Salry after deduction is " +AnnualSalary / 12);
            }
        }
    }
}

Below code snippet shows that first we are creating a instance of TestMultiCastDelegate and passing the reference of methods [GetSalary] and [GetSalaryAfterDeduction] with  "objDelegate2".
MultiCastDelegateExample objMultiCastDelegateExample = new MultiCastDelegateExample();
 
//Creating the instance of the delegate
TestMultiCastDelegate objDelegate2 = null;
 
//Referencing the multiple methods using + sign
objDelegate2 += objMultiCastDelegateExample.GetSalary;
objDelegate2 += objMultiCastDelegateExample.GetSalaryAfterDeduction;
objDelegate2.Invoke(60000);
 
 
 Delegates are immutable, so when you call += or -=, you’re in fact creating a new delegate instance and assigning it to the existing variable.

All delegate types implicitly derive from System.MulticastDelegate, which inherits from System.Delegate. C# compiles +,-, +=, and -= operations made on a delegate to the static Combine and Remove methods of the System.Delegate class.

 How to achieve callback in Delegate?
Callback is term where a process is going on and in between it targets some achievement then it returns to main method. For callback, we just need to encapsulate the method with delegate.
objCallBackMethodExample.CheckEvenEvent += new OnEvenNumberHandler(objCallBackMethodExample.CallBackMethod);
Let see an example, CallBackMethodExample is a class which have a method CallBackMethod. It will be executed when some criteria will be fulfill. 
public delegate void OnEvenNumberHandler(object sender, EventArgs e);
 
public class CallBackMethodExample
{
        public void CallBackMethod(object sender, EventArgs e)
        {
            Console.WriteLine("Even Number has found !");
        }
}
When we are going to call this method using Delegate for callback, only need to pass this method name as a reference.
CallBackMethodExample objCallBackMethodExample = new CallBackMethodExample();
 
objCallBackMethodExample.CheckEvenEvent += new OnEvenNumberHandler(objCallBackMethodExample.CallBackMethod);
Random random = new Random();
for (int i = 0; i < 6; i++)
{
   var randomNumber = random.Next(1, 10);
   Console.WriteLine(randomNumber);
   if (randomNumber % 2 == 0)
   {
       objCallBackMethodExample.OnCheckEvenNumber();
   }
}
 
How to achieve Async callback in Delegate
Async callback means, process will be going on in background and return back when it
will be completed. In C#, Async callback can be achieved using AsyncCallback
predefined delegate as following.

public delegate void AsyncCallback(IAsyncResult ar);
 
Kindly follow the following example to understand the Async callback. There is a class name as CallBackMethodExample which have two method, one is TestMethod and other one is AsyncCallBackFunction. But as we can see AsyncCallBackFunction is taking IAsyncResult as a parameter.

public delegate void OnEvenNumberHandler(object sender, EventArgs e); 

public class CallBackMethodExample   
 {                
    public void TestMethod(object sender, EventArgs e)   
     {   
         Console.WriteLine("This is simple test method");   
     }         
 
   public void AsynCallBackFunction(IAsyncResult asyncResult)      
   {          
      OnEvenNumberHandler del = (OnEvenNumberHandler)asyncResult.AsyncState;      
      del.EndInvoke(asyncResult);     
      Console.WriteLine("Wait For 5 Seconds");      
      Console.WriteLine("...");        
      Console.WriteLine("...");         
     Console.WriteLine("...");         
     Console.WriteLine("...");      
     System.Threading.Thread.Sleep(5000);    
     Console.WriteLine("Async Call Back Function Completed");   
     } 
   } 

When we are going to invoke the delegate, only just need to pass AsycnCallBackFunction with delegate
instance. 


CallBackMethodExample objCallBackMethodExample = new CallBackMethodExample(); 
 
OnEvenNumberHandler objDelegate3 = new OnEvenNumberHandler(objCallBackMethodExample.TestMethod); 
 
objDelegate3.BeginInvoke(null, EventArgs.Empty, new AsyncCallback(objCallBackMethodExample.AsynCallBackFunction), objDelegate3);
 
Console.WriteLine("End of Main Function"); 
Console.WriteLine("Waiting for Async Call Back Function");
 

---------------------------------------------


Delegates that don’t accept any parameters can be handled using Lambdas. Eg

delegate bool LogDelegate();
Static void Main(string[] args)
{
   LogDelegate del =  ()=> {
                                                 UpdateDatabase();
                                                  WriteEventToLog();
                                                  return true;
                                             };

bool status= del(); //execute the delegate
}


.Net framework provides some built in delegates. Eg. 
Action<T>   it accepts a single parameter and returns no value.
Func<T, TResult> it accepts a single parameter and returns a value of type TResult.

Public Static void Main(string[] args)
{
  Action<string> messageTarget;

  If(args.Length > 1)
            {
                   messageTarget = ShowWindowsMessage;
           }
  else {
            messageTarget = console.writeline;
          }

    messageTarget(‘Invoking action’);
}


Public static void ShowWindowsMessage(string message)
{
  MessageBox.Show(message);
}


·         Action<int, int> myAction = (x,y)=> console.writeline(x+y);
data.Processaction(2,3, myAction);

public void Processaction(int x, int y, Action<int, int> theaction)
{
    theaction(x, y);
    console.writeline(action has been processed.‘’);
}



Public Static void Main(string[] args)
{
   Func<string, bool> logFunc;
  If(args[0] == “EventLog”)
    {
      logFunc = LogToEventLog;
    }
else
  {
    logFunc = LogToFile;
  }

bool Status = logFunc;
}

Private static bool LogToEventLog(string message) { /* log the message*/}
Private static bool LogToFile(string message) { /* log the message*/}



-With Action<T> and Func<T, TResult> we don’t have to write custom delegates.

-         Func<int, int, int> funcAddDel = (x, y)=> x+y;
data.Process(2,3, funcAddDel);

public void Process(int, int, Func<int,int,int> del)
{
    var result = del(x,y);
    console.writeline(result);
}
 




A delegate also can be thought of as an object that contains an ordered list of methods with the same signature and return type.
  1. The list of methods is called the invocation list.
  2. When a delegate is invoked, it calls each method in its invocation list.
For static methods, a delegate object encapsulates the method to be called. For instance methods, a delegate object encapsulates both an instance and a method on the instance.
An interesting and useful property of a delegate is that it does not know or care about the class of the object that it references. Any object will do; all that matters is that the method's argument types and return type match the delegate's. This makes delegates perfectly suited for "anonymous" invocation.

Delegates vs. Interfaces

Delegates and interfaces are similar in that they enable the separation of specification and implementation. Multiple independent authors can produce implementations that are compatible with an interface specification. Similarly, a delegate specifies the signature of a method, and authors can write methods that are compatible with the delegate specification. When should you use interfaces, and when should you use delegates?
Delegates are useful when:
  • A single method is being called.
  • A class may want to have multiple implementations of the method specification.
  • It is desirable to allow using a static method to implement the specification.
  • An event-like design pattern is desired (for more information, see the Events Tutorial).
  • The caller has no need to know or obtain the object that the method is defined on.
  • The provider of the implementation wants to "hand out" the implementation of the specification to only a few select components.
  • Easy composition is desired.
Interfaces are useful when:
  • The specification defines a set of related methods that will be called.
  • A class typically implements the specification only once.
  • The caller of the interface wants to cast to or from the interface type to obtain other interfaces or classes.

Subscribers have full access to the delegate which means they are capable of adding more subscribers or removing an existing subscriber without that subscriber’s knowledge, which is bad. This problem is called as Naked Delegate Exposure.
Delegates should not be exposed to the subscribers which means if we need to encapsulate the delegate from subscribers to avoid them to make any changes, this encapsulation is called Events.
A Delegate which needs to be encapsulated by Event must be of return type void and in general has two parameters, first the sender of the event and second the arguments which need to be passed when the event is fired.



    0 comments:

    Post a Comment

    Twitter Delicious Facebook Digg Stumbleupon Favorites More