Pages

Sunday, October 25, 2015

Delegates and events

A delegate in c# are variables that hold a reference to a function. It can reference more than one function (multicast). When the delegate is called, it will invoke all functions assigned. If return values are given, the return value of the delegate will be from the last function invoked.

Example:

public delegate string MyDelegate();

MyDelegate myDel = SomeFunction;   // this is short hand. Might see "new MyDelegate(SomeFunction)"

myDel += AnotherFunction;  // multicasting. Adding additional functions. 


var return = myDel();  // both functions will be invoked but return will hold "another"


public string SomeFunction()
{
    return "some";
}

public string AnotherFunction()
{
    return "another";
}


Rules can bend for delegate signature matches. It is a result of inheritance,

The delegate return value must match the return type of the function assigned to the delegate except in cases of covariance. Covariance is when the return type (Dog) of the function is derived from the return type (Animal) of the delegate. 

COVARIANCE:

delegate Animal MyCovarDelegate();     

MyCovarDelegate myCovDel = FindDog;

public Dog FindDog();  // Dog (function return type) is derived from Animal (delegate return type)

public class Animal
{
    public string type;
    public boolean mammal;
}

public class Dog : Animal
{
    public string breed;
}


The delegate parameter type must match the parameter type of the function except in cases of contravariance. Contravariance is when the param type (Dog) of the delegate is derived from the param type (Animal) of the function. It is reverse/contra of covariance. 

CONTRAVARIANCE:

delegate void MyContraDelegate(Dog d); // Dog (delegate param type) is derived from Animal (function return type)

MyContraDelegate myConDel = ViewDog;

public void ViewDog(Animal a); 


Why Delegates?

1) Is used to handle events (shown below).
2) Allows programs to run methods at run time without knowing the methods at compile time.
2a) Objects can be decoupled between publishers and subscribers. Publisher has no idea who is subscribing nor what the subscriber is doing. It simply creates an event, when the event is raised, it checks to see if there are any subscribers. If subscribers, then it runs the EventHandler (which contains a list of methods (points to methods) that are set to run).
2b) By creating a new class and simply subscribing to the existing event that is published, you can add new classes and attach to events without modifying the original code. Hence, less chance of code breakage. 
3) Achieves Inversion of Control (IOC) when a framework/library wants to call you.
4) Can pass delegates as a parameter to a function.


public class Person
{
     public delegate void MyEventHandler();
     public event MyEventHandler cashEvent;

     public void AddCash()
    {
        If (cash > 5 )    // some event occurs
                   {
                      If (cashEvet != null)   // check for subscribers
                                           {
                                                cashEvent();   // fire event
                                           }
                   }
    }
}

public class Hello
{
     Person p = new Person();
     p.cashEvent += p_cashEvent;      // subscribe to event and assign function(s) to invoke
    
    public void p_cashEvent()
    {
      // do something
    }
}


*****

Func <T> and Action <T> are .net built in delegates