Page 1 of 1

Delegates, Lambdas and Events

#1 CodingSup3rnatur@l-360  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 992
  • Posts: 972
  • Joined: 30-September 10

Posted 06 March 2011 - 08:05 AM

*
POPULAR

Learning C# Series


Delegates, Lambdas and Events

Welcome to my tutorial on delegates, lambdas and events. These can be difficult concepts to grasp at first. I am going to be trying to make it as clear as possible for you :).

Why is this important to learn about?

The compelling reason to learn delegates is that other parts of the .NET framework rely heavily on delegates (LINQ and multithreading libraries being two big examples). An event is just a delegate, and lambdas are just short ways to write methods of which are encapsulated by delegates.

Further, events are central to the windows GUI environment (button clicks, etc), and are vital if you want classes to communicate in a loosely coupled manner.

They are a key topic to learn as they are big part of the framework, and they play a big part in making the framework as flexible as it is :)


Definitions of terms used.


Encapsulation – The principle of hiding members (methods, fields etc) inside a class.

Decoupled – To decouple two classes is to disconnect them so that they can do their work independently, without relying heavily on each other.

Abstraction – This is the process of simplifying complex problems.

Type Safe - Type safety is the extent to which a programming language discourages or prevents type errors. A type error is erroneous or undesirable program behaviour caused by a discrepancy between differing data types.

Event Driven Programming – The art of controlling program flow by raising and handling events.


Note: All examples were created using Visual Studio 2010, targeting the .NET Framework 4.0. We'll do our best to point out anything that might not work in older versions.


Delegates, Lambdas and Events

Before we begin, note that all examples are written in a console application.

Plus, you should have a good understanding of all the beginner topics in the series, and a firm grip of at least the first 4 intermediate topics. See the Learning C# Series thread for details :).



Delegates

The standard description of a delegate is a type safe function pointer.

Basically, a delegate is a type that encapsulates one or more methods. You can invoke all the methods the delegate is encapsulating with a single call, whenever you wish.

I shall begin by defining a delegate type, then I shall create an instance of the delegate type and explain the various things that can be done with a delegate type.

As we proceed, I shall do my best to explain what is happening behind the scenes when you declare and use delegates. It is important to have a general idea of what the compiler does behind the scenes, as it will help your understanding :).


First create a new class called MyDelegates, and explicitly implement a default constructor so your class looks like this:

class MyDelegates
{
    public MyDelegates()
    {
            
    }
}




Defining the delegate type

In that class, create a delegate type using a delegate keyword, as follows (put this above the constructor from this example), so the code becomes:

class MyDelegates
{
        public delegate void PerformAction(double firstNumber, double secondNumber);

        public MyDelegates()
        {

        }
}




Okay, that delegate type is called PerformAction, and it can encapsulate one or more methods that take two doubles as arguments, and has a return type of void.

However, what actually happens on that line?

You will notice I say delegate type. I do this very deliberately, as an awful lot is done behind the scenes when that line is executed.

In fact, a brand new class is created, called PerformAction. This class inherits from the MulticastDelegate class, of which itself inherits from the Delegate class. As such, the created class inherits the members of those two classes.

The MulticastDelegate class represents a delegate that can ‘hold’ multiple methods. The Delegate class represents a delegate that can only 'hold' a single method. However, as classes created using the ‘delegate’ keyword (as we have done with the PerformAction above) inherit directly from MulticastDelegate, and indirectly from Delegate, the delegates that we define using the ‘delegate’ keyword can 'hold' both single methods, and multiple methods.

There are 3 members inherited from these two classes that I am interested in for this tutorial.

The first 2 are properties inherited from the Delegate class. They are called ‘Target’ and ‘Method’, and are read only. The ‘Method’ property holds a MethodInfo object (see Reflection tutorial for more details) that essentially encapsulates the meta-data for the method the delegate is encapsulating. So, basically, think of it as being used to hold a reference to single method.

The ‘Target’ property holds (or the field the property encapsulates does) the instance that the method held in ‘Method’ is a part of. If the method is static, it is assigned null.

The third member of interest is a method called GetInvocationList(). This gets an array of Delegate objects. The PerformAction class will have an internal list that holds delegates, each of which 'holds/points to' a method. This internal list is what allows a delegate to 'hold/refer to' multiple methods.


The point to hammer home is that a new class is created when public delegate void PerformAction(double firstNumber, double secondNumber); is seen, and this class can hold a single method, or a list of methods. You are defining a class when you use the ‘delegate’ keyword as above.


Creating a field to hold an instance of the delegate type

Now we have defined our delegate class (PerformAction), as with any non static, non abstract class, we have to make an instance of it to be able to use it.

We begin by creating a variable of type PerformAction, as so; public PerformAction actions;, so the code becomes:

class MyDelegates
{
        //define delegate type
        public delegate void PerformAction(double firstNumber, double secondNumber);

        //I don’t usually recommend making fields public
        //but just for ease of example, this field is public here.

        //This is our delegate (i.e. an variable of a delegate class type!
        public PerformAction actions;

        public MyDelegates()
        {

        }
}



That is no different to how you have declared variables to hold references to any other class. Remember, PerformAction is just a class.


Defining a method for the PerformAction variable to encapsulate

Still in the MyDelegates class, define this method:

//signature and return type matches types demanded by delegates
private void Add(double operand1, double operand2)
{
            //calculate sum total
            double total = operand1 + operand2;
            
            //print out sum total
            Console.WriteLine("Sum total is {0}", total);
}



We are going to have our PerformAction delegate 'hold/refer to' this method.

Instantiating the PerformAction class

Think about this for a second, PerformAction is a class, how do we instantiate classes?

Add this line to the default constructor of the MyDelegates class:

this.actions = new PerformAction(Add);



so the code becomes:

lass MyDelegates
    {
        //define delegate type
        public delegate void PerformAction(double firstNumber, double secondNumber);

        //I don’t usually recommend making fields public
        //but just for ease of example, this field is public here.

        //This is our delegate (i.e. an variable of a delegate class type!
        public PerformAction actions;

        public MyDelegates()
        {
            this.actions = new PerformAction(Add);
        }

        //signature and return type matches types demanded by delegates
        private void Add(double operand1, double operand2)
        {
            //calculate sum total
            double total = operand1 + operand2;
            
            //print out sum total
            Console.WriteLine("Sum total is {0}", total);
        }
    }



All we are doing in the constructor is creating a new PerformAction instance (using the ‘new’ keyword, and passing in the name of a method (of which must take two doubles, and have a return type of void, as that is the signature demanded by our delegate) that we want the PerformAction class to encapsulate.


Congratulations, you have created a delegate that encapsulates a single method (single cast delegate). This method will be held in the field behind the ‘Method’ property of the PerformAction class. The instance of the MyDelegates class (when we create one to allow us to use it), will be held in the ‘Target’ property of the PerformAction class.


Further, there is a shortcut to instantiating the PerformAction class and encapsulating Add() within it. You can just do this:

this.actions = Add;


and all the instantiation of the PerformAction class will be done for you!

I think it is shortcuts like this that add to the confusion, plus the fact that so much is abstracted away from you (the creation of the class when you use the ‘delegate’ keyword, for example).

Shortcuts are handy once you have learned the ins and outs though ;).


Calling the method that the delegate is now holding

Create an instance of the MyDelegates class in the Main() method of the console application:

MyDelegates example = new MyDelegates();



You can then access the delegate field as you access any public member of an instance:

example.actions(2.3, 5.6);


Here is the current code in Main():

static void Main(string[] args)
{
            MyDelegates example = new MyDelegates();
            example.actions(2.3, 5.6);
            Console.ReadKey(true);
}



Because the PerformClass instance held in the ‘actions’ field encapsulates Add(), we can call the method through the delegate instance, just like we were calling the Add() method directly.

Notice that in the same way that interfaces and abstract classes abstract the user of classes away from the implementation details (i.e. they do not need to know how the classes work in order to use them, they just need to know that they produce certain results), delegates do this for methods.

It does matter to the calling code (the code in Main()) how the method encapsulated by the delegate does its work, it only cares that it takes two double arguments, and has a return type of void. Add() is actual private in the MyDelegates class, so the code in Main() has absolutely no idea how the Add() method is doing its work, and how MyDelegates does its work. It just knows that MyDelegates has a delegate that can be invoked that may, or may not, give one or more doubles back.

This means (although this example is obviously contrived), we could completely change how the MyDelegates class does its work, and completely change the method(s) held in the 'held' in the PerformAction delegate, and the code in Main() (the calling code) would be completely ignorant of these changes, and would therefore not have to change at all!

This idea of decoupling calling code from the horrible, complex implementation details makes great design sense, and will greatly help maintainability and reuse.

In that way, delegates are like interfaces for methods.

If you run the program now, you should get this output:

Quote

Sum total is 7.9


Now, what if you want to encapsulate multiple methods using a single delegate field? The class PerformAction has the capability to hold references to multiple methods (with its privately implemented invocation list), but how do we add methods to the invocation list?


Encapsulating multiple methods with a single delegate field

The class that is automatically created with the ‘delegate’ keyword in the initial declaration of the delegate type has overloaded the += and -= operators.

They have been overloaded to allow methods to be added and removed from the delegate’s (the PeformAction class) invocation list.


Before we add the methods to the invocation list however, we need to create them!

Therefore, ensure you have all these methods in the MyDelegates class:

private void Add(double operand1, double operand2)
        {
            //calculate sum total
            double total = operand1 + operand2;

            //print out sum total
            Console.WriteLine("Sum total is {0}", total);
        }

        private void Subtract(double operand1, double operand2)
        {
            //calculate difference
            double difference = operand1 - operand2;

            //print out difference
            Console.WriteLine("Difference total is {0}", difference);
        }

        private void Multiply(double operand1, double operand2)
        {
            //calculate product
            double product = operand1 * operand2;

            //print out product
            Console.WriteLine("Product is {0}", product);
        }

        private void Divide(double operand1, double operand2)
        {
            //calculate quotient
            double quotient = operand1 / operand2;

            //print out quotient
            Console.WriteLine("Quotient is {0}", quotient);
        }




Adding these methods to our delegate instance’s invocation list

Using the overloaded operator; +=, we can add these methods to our delegate’s invocation list. Add these lines to the MyDelegate class constructor:

this.actions += new PerformAction(Subtract);
this.actions += new PerformAction(Multiply);
this.actions += Divide; //shortcut version again



so that the code becomes:

Spoiler


Recall that the PerformAction class will have an internal invocation list of which actually hold objects of Delegate type, or children thereof. Therefore, we instantiate new PerformAction objects/delegates, passing in the names of the methods to add, and then add them to the invocation list using the overloaded += operator.

Notice the shortcut version again (this.actions += Divide;). Just naming the method is actually more logical in this example. We think of it as adding methods to the delegates invocation list (even though we are actually adding delegate instances, of which encapsulate the methods, to the invocation list).

This shortcut compliments that way of thinking and helps readability. By looking at that third line, we can instantly see that we are adding the Divide method to ‘actions’ invocation list.

Generally speaking, when a new instance of a delegate type is expected (i.e. new PerformAction(methodNameHere)), you can just specify the method name as a shortcut, and skip the explicit instantiation with the new operator.

You should also note that you don’t have to have this line:

this.actions = new PerformActions(Add);



You can just use the following lines to add all the methods to the invocation list, without explicitly assigning an instance to ‘actions’ first. It is taken care of for you!

this.actions += Add;
this.actions += Subtract;
this.actions += Multiply;
this.actions += Divide; 



So, the code becomes:

Spoiler


Now, you can execute the program again, and it will produce 4 lines of output.

You should see this output (regardless of which version of the MyDelegates constructor you now have):

Quote

Sum total is 7.9
Difference total is -3.3
Product is 12.88
Quotient is 0.410714285714286


Now, a key point has arisen here. Did you notice how we made those changes to our class, adding methods to the invocation list of the PerformAction instance etc, but we made absolutely no change to the calling code (the code in Main()).

This is demonstrates perfectly the principle of decoupling and abstraction. Because all the calling code cares about is that the delegate type PerformAction holds methods taking two doubles, and returning a double, it doesn’t care about the implementation details of the methods encapsulated in the PerformAction instance, nor does it care how many methods are encapsulated. It just calls the delegate as if it were a method itself, and lets the compiler and our MyDelegate class take care of the details of what happens from there.

This means changes to our class doesn’t affect calling code (our clients). This is your first glimpse at the power of delegates (and events) in building well designed, maintainable, flexible software!

Now we have added multiple methods to the invocation list of the PerformAction delegate class using its overloaded += operator, we are using it as a multicast delegate. All those methods are called when this single line in Main() is executed:

example.actions(2.3, 5.6);


Finally, you can remove methods from the delegate type's invocation list in exactly the same way using the -= operator instead of the +=.

For example, to remove the Add() method from the invocation list, you could do this in the MyDelegates class:

this.actions -= Add;



Note: Delegates are immutable. This that when we add to a delegate's invocation list, what we are actually doing is creating a brand new delegate instance, of which has the new item added to its invocation list. Delegate instances cannot be changed once constructed.


Events


What you saw in the previous example (with the adding of the methods to the invocation list), was the most basic kind of event.

You are adding methods to the invocation list of a delegate, and executing them when you see fit. This is what an event is! For example, you could do something like this in the Main() method:

MyDelegates example = new MyDelegates();

if(Console.ReadLine().ToUpper().Equals("CALCULATE") && example.actions != null) 
{
   example.actions(2.3, 5.6);
}




you are technically (although not in proper .NET terminology) raising an event (albeit in quite a poor manner, but we’ll tidy it up in a minute). You are saying, if the user enters ‘calculate’ (or any other case variant), execute the four methods sitting in the invocation list of the PerformActions delegate type, in response to that event. You are raising an event, and responding to it by performing different actions (the four methods).

That is the basic principle of events.

However, the above example needs tidying up to confirm to basic design principles and best practices, and to use actual .NET events which are a dedicated feature built into C#. .NET events use delegates to perform their work, but are actually more than just simple delegates.

The first problem with the way we are raising the event above is that Main() is raising an event directly that is defined in another class (namely, MyDelegates). This is not good design.

It is MyDelegates’ event, so that should be the only class that can raise it directly.

You may immediately think we can fix this problem by making our delegate field private:

private PerformAction actions;


so only members in the MyDelegates class can access it, and therefore raise it. However, the idea with events is that other classes register with the event (by adding methods to the delegate’s invocation list using the += operator), and the registered method(s) gets executed when the event is fired. In order to add methods to the invocation list of the PerformAction, other classes need to access it, so we cannot make it private.

How do we overcome this problem?

The ‘event’ Keyword

The answer is to use the ‘event’ keyword on the delegate field like this:

public event PerformAction actions;


Now, what that does is special, yet simple.


The compiler actually implements the field as a private field, even though it is declared public by us. The compiler encapsulates a private delegate field behind a kind public property that allows users to add and remove methods from the delegate's field's invocation list only.

The property created provides restricted access to the delegate field. Instead of get/set accessors however, this special property has add and remove accessors that allow external classes to add and remove methods from the delegate's invocation list, of which are still mapped to the += and -= operators.

The end result is that other classes can access the field ONLY to add (or remove) methods to the invocation list (register with the event), but they cannot fire the event directly with the example.actions... line, as they no longer have direct access to the now privately implemented delegate field.

ONLY the class the event is defined in can fire the event directly.

That is what the 'event' keyword is for. To restrict access so that external classes can't directly fire the event. They can only subscribe and unsubscribe from the event. It's really that simple!

You should always use the ‘event’ keyword when defining events, for the simple reason outlined above.

Here is a basic, rough example of what the compiler produces when it sees the event keyword in the context of our PerformAction delegate, if we changed this line:

public PerformAction actions;


to

public event PerformAction actions;


Spoiler


For more detailed information on how events are implemented by the compiler, in code, and precise detail on how events use delegates, see this topic.


The EventHandler<TEventArgs> delegate type

EventHandler<TEventArgs> is a delegate type (just like PerformAction was a delegate type), that is predefined within the .NET framework.

Now, at this point, you should note that it is standard that methods that are to be called in response to an event (that have been added to the delegate’s invocation list), should take two parameters (as recommended by MSDN):

  • Object sender
  • EventArgs e


EventHandler<TEventArgs> (a generic delegate) is defined like this:

public delegate void EventHandler<TEventArgs>(
	Object sender,
	TEventArgs e
)
where TEventArgs : EventArgs



This enforces the best practice structure of all methods that are executed in response to events, and so should be used for our custom events. The ‘sender’ argument is the instance that the event was fired on, and TEventArgs is any class that derives from (or is) the EventArgs class. It should hold any data associated with the event.

Using this argument, we can pass values between classes using events.

(see more on predefined delegates in Predefined delegate types in .NETsection)

(Note: This delegate is concerned largely with creating custom events (as we are doing in this example). Other predefined events in the .NET framework often make use of other delegate types. For example, the MouseDown, MouseUp and MouseMove events in the WinForms use the MouseEventHandler delegate. This delegate can encapsulate a method that takes the 'object sender' and a second parameter of type MouseEventArgs.)


Implemented a Best Practice Event Pattern

So let’s implement a correct, best practice event pattern using our MyDelegates class:

Firstly, we are going to remove everything apart from an empty default constructor from our MyDelegates class.

Then, we are going to define an event called ActionPerformed (it is standard to provide events with names describing actions using verbs), and add a method that we can use to raise the event whenever we like. As such, your class should look like this:

class MyDelegates
    {
        //just another delegate field that uses the event keyword
        //We don’t need to define the EventHandler delegate type
        //as it is already defined in the .NET framework
        public event EventHandler<EventArgs> ActionPerformed;

        public MyDelegates()
        {
          
        }
         
        protected virtual void OnActionPerformed(EventArgs e)
        { 
            //temp delegate field
            EventHandler<EventArgs> tempHandler = this.ActionPerformed;
            //if delegate has some methods to invoke, invoke them
            //or ‘raise the event’
            if (tempHandler != null) tempHandler(this, EventArgs.Empty);

        }

       
    }





‘ActionPerformed’ is the name of the event, and the delegate is of type EventHandler<EventArgs> meaning that all methods that get added to it’s invocation list must have a return type of void, and must take two parameters, the first being a parameter of type object, the send being a parameter of type EventArgs (or a type derived thereof).

The method we use to raise the event tests if the delegate field is equal to null. If it is, it means it isn’t encapsulating any methods, and so trying to execute encapsulating methods would cause a NullReferenceException to be thrown, as there aren't any methods to call!

But why do we use the ‘tempHandler’ variable?

The reason is to avoid a race condition whereby the last method in the invocation list of the EventHandler<EventArgs> delegate is removed by code executing on another thread, in between the test for null, and the firing of the event. So, the event would get fired, even though there are no methods to invoke, causing the NullReferenceException to be thrown.

The firing of the event should be familiar to you. Remember how we executed all the methods that the PerformAction delegate was encapsulating? Well, this is exactly the same thing! We are telling the runtime to execute every method that is encapsulated in the EventHandler<EventArgs> delegate instance.

We pass in the current instance to the first parameter (as the first parameter is supposed to be the instance on which the event is fired) and an EventArgs instance. We pass an EventArgs instance into the OnActionPerformed method so that we have the option in the future of passing in data to by carried with the event.

Remember, that delegate encapsulates methods taking these two parameters, so we have to pass in the parameters in the delegate invocation, of which are then passed to each of the methods that the delegate is encapsulating.

In this example, we are going to call OnActionPerformed() in a trivial manner. When the calling code passes the number 5 to a method called DoSomething(), the event is going to be fired. So, with the DoSomething() method added, here is the finished code for the MyDelegates class:

class MyDelegates
    {
       // public delegate double PerformAction(double firstNumber, double secondNumber);

        public event EventHandler<EventArgs> ActionPerformed;

        public MyDelegates()
        {
          
        }

        public void DoSomething(int i)
        {
            if (i == 5) this.OnActionPerformed(EventArgs.Empty);

        }

        protected virtual void OnActionPerformed(EventArgs e)
        {
            EventHandler<EventArgs> tempHandler = this.ActionPerformed;

            if (tempHandler != null) tempHandler(this, e);

        }

       
    }




Notice we pass EventArgs.Empty to the OnActionPerformed. This is because we don’t want to pass any data with the event in this example. If we did, we would create our own custom class, of which derived from EventArgs, that could hold our event data, and we could then pass an instance of that class into the method, meaning data would be passed with the event, and would be accessible from the subscribing classes (the classes that access the event, and add methods to the invocation list).

The reason that the OnActionPerformed method is protected and virtual is to allow derived classes to respond to the event (without exposing the method to the world by making it public), without adding a method to the invocation list of the delegate behind the event.

A class derived from MyDelegates class that overrides OnActionPerformed() must always call the OnActionPerfromed method of the MyDelegates class to ensure that registered delegates receive the event. You call base class methods using the 'base' keyword :)


Listening for an event

The Main method is going to contain code to listen for MyDelegate’s event, and respond to it. How can it do this? Well, remember that when the event is fired, an invocation list of methods is executed. Therefore, we just need to add methods to this invocation list, and they will be executed when the event is fired.

We already know how to do this!

So just add this method to the Program class (where your Main method is) (it’s static purely and simply so I can access it from Main(); no other reason :));

private static void example_ActionPerformed(object sender, EventArgs e)
        {
            Console.WriteLine("The type of the object that raised this event is {0}", sender.GetType());
        }



That will print out the type of object that fired the event, when the event occurs, using the ‘sender’ parameter. If we passed any data with the event, we could access that data through the parameter ‘e’.

Now we need to add that method to the invocation list of the EventHandler<EventArgs> delegate. To do this, clear anything you currently have in Main(), and add these lines:

 static void Main(string[] args)
        {
            //create instance of class
            MyDelegates example = new MyDelegates();

            //add example_ActionPerformed method to the invocation list.
            //Otherwise called registering with the event.
            example.ActionPerformed += new EventHandler<EventArgs>(example_ActionPerformed);

            //raise event using simulation by passing in 5
            //to the do something method, of which will consequently
            //raise the ActionPerformed event.
            example.DoSomething(5);
        }




Here is the final code that raises and handles an event:

Spoiler


Now, run the application.

You should see a message to this effect printed:

Quote

The type of the object that raised this event is [nameOfYourNamespace].MyDelegates"


Congratulations, you successfully fired (in the MyDelegates class) and handled (in the Program class) an event!

TIP: When you have written part example.ActionPerformed +=, you should be able to press ‘tab’ and the rest of the code will automatically be inserted for you! That is another advantage of using the ‘event’ keyword!

The calling code in Main() doesn’t care how or when the ActionPerformed event is fired. All it cares about is that it may be fired at some point, and if it is fired, the example_ActionPerformed method is run, along with any other methods we may add to the invocation list.

The standard for naming handler methods (methods added to the event delegate’s invocation list) is the name of the instance they are invoked on (‘example’ in this case), followed by an underscore (_), followed by the name of the event (‘ActionPerformed’ in this case).

This kind of ignorance through abstraction that events bring, help to create flexible and maintainable code :).

It is also standard, for reusability sake, to not put any complex logic in the handler methods. You should created dedicated methods, and then call them from the handler methods, rather than putting code directly in the handler methods.


Note: You can obviously subscribe (add to the delegate’s invocation list) as many methods as you want to respond to the event. You can also remove methods using exactly the same syntax, but replace += with -=.

If the event listener object is likely to live longer (i.e. be in scope for longer) than the event publisher object, you should strive to de-register events by removing the methods from the delegate's invocation list using the -= operator, otherwise memory leaks can arise.

Click here for an article on events and memory leaks.


Using delegates to pass methods to other methods

Now, for this example, I am going to use the example of the FindAll() method of the List<T> class.

I am going to create my own version of this method that can operate on all collections that implement ICollection<T>.

The idea behind the method is that it search a collection for elements that match a specified condition; it returns all elements that match the condition.

Immediately, we hit a problem. How the hell do we allow the user to specify what condition to use? This method will be a non-constrained generic, and so it could be acting on practically any type (string, int, custom object, double etc). This surely requires an impossible amount of flexibility, as there are an infinite amount of different conditions that our users may want to use to extract elements (get all elements with values below 50, get all names greater than 5 letters in length, get all people with more than 10 dogs).

The possibilities are quite literally, infinite!

Fortunately, we can use delegates to add infinite flexibility!

Right, start by opening up a new console application and creating a class called MyCollectionSearcher.

Implement the class like this:

public class MyCollectionSearcher<T>
    {
        //collection to search
        private ICollection<T> collection;

        //constructor that takes a collection
        public MyCollectionSearcher(ICollection<T> collection)
        {   //assign passed collection to field
            this.collection = collection;
        }
        //my FindAll() method
        public IEnumerable<T> FindAll(Predicate<T> searchFunction)
        {
            //collection to hold elements that match the condition
            ICollection<T> matched = new List<T>();

            //loop through each element in the passed in collection
            foreach (T element in this.collection)
            {
                //call method encapsulated by delegate on each element
                //and add element to matched collection if the method
                //call return true
                if (searchFunction(element)) matched.Add(element);
            }

            return matched;
        }
    }




(NOTE: Instead of creating a separate list ('matched') to hold matched elements, we could utilise a 'yield return' statement to return all matches. That would overcomplicate things unecessarily for this tutorial however :))


That may all seem very confusing, so I shall go through it step by step.

The first point to note is that this class is meant to wrap a collection of items, i.e. it holds an internal collection of items. We pass in the collection we want to search into the constructor, and store the collection in the ‘collection’ field. Then, when we can call FindAll(), and it will search that particular collection.

In the Main() method, instantiate the above class, and pass to it a list of integers, as so:

MyCollectionSearcher<int> searcher = new MyCollectionSearcher<int>(new List<int>() { 1, 2, 3, 4, 6, 43, 4, 6, 7, 5, 4, 4, 5, 7, 8, 6, 4 });


This MyCollection instance now holds/wraps that list of integers internally.

Now, say we want to search that list, and return a list of all the integers that are greater that 5 in the list, using our FindAll() method.

The FindAll() method takes a delegate of type Predicate as an argument. So, what on Earth do we pass in that will allow us to find numbers greater than 5?

Predefined delegate types in .NET

I think now would be a good time to (re)introduce the fact that the .NET framework has already defined some delegate types (or classes, just as we defined the PerformAction class with the delegate keyword earlier). These delegate type are just like the delegate types we could define ourselves. They can encapsulate method's with certain common signatures and return types.

They mean that we don't ALWAYS have to define our own delegates :).

The names of the 4 of the most widely known (all 4 are defined in the System namespace), more general predefined delegate types (although there are many, many, many(!!!) more predefined delegates...Think about all the events associated with windows form events. For example, the KeyPress event uses a KeyPressEventHandler delegate type) are:




And, as you would imagine, each of the different predefined delegate types encapsulate methods with different signatures and return types.

These predefined delegates exist purely to save us some time. It means that we don’t always have to define our delegate types ourselves!

Here is how the delegate of Predicate type is defined:

public delegate bool Predicate<in T>(T obj);


It defines a method that returns a bool, and takes an object of generic type as a parameter. Nothing special here!

I could have easily defined my own delegate called MyPredicate, like this:

public delegate bool MyPredicate<in T>(T obj);


It is basically the same as the Predicate delegate in the method it can encapsulate, but it is just of type MyPredicate instead.

What’s the point of defining my own delegate when a predefined one already exists? So, in my FindAll(), I have used the already defined Predicate delegate type.


Back to the example

Right, so we have established that FindAll() is expecting a Predicate delegate to be passed as an argument, and that the Predicate delegate type encapsulates a method accepting an object of generic type as a parameter, and is of return type bool.

As we have instantiated our generic class with an ‘int’ type, our FindAll() method in the instance called ‘search’ accepts an int argument (thanks to generics).

Let’s look at our FindAll() method.

We first declare a collection that is used to hold all the elements found.

We then loop through each item in the collection held in the ‘collection’ field (our list of integers in our example). Now, for each element in the collection, we pass it to the method encapsulated by the delegate of type Predicate.

Remember, Predicate is a class that encapsulates a method. This statement:

searchFunction(element);


is therefore equivalent to calling that encapsulated method. We are meant to pass in the encapsulated method to FindAll() using a Predicate instance.

Remember, as we will be working with a list of integers, ‘T’ is of type int, and so the method encapsulated by ‘searchFunction’ accepts an int also. Recall further that the method must return a bool, and therefore the returned value can be used in an if statement.

Now, if it returns true, we add the current element to the ‘matched’ collection, else, we just continue looping through the remaining elements.

Once we have gone through each element, we return the ‘matched’ collection.

Now, behold the power of delegates...…

We only added elements to a collection when the method encapsulated by the Predicate parameter returns true. Therefore, the callers of FindAll() are able to define a method that takes an int as a parameter, and returns a bool that indicates whether or not the current int element matches a condition entirely of their choice. And pass that into FindAll().

For example, I want to use FindAll() to extract all the numbers that are greater than 5 in the collection held in the ‘searcher’ instance.

Firstly, I define the method that will determine if the current integer is greater than 5, i.e. our Predicate method. Here it is:

(defined in the Program class of the console application. Once again, it is declared static purely so I can access it from Main(). It has nothing to do with the delegates example)

private static bool GreaterThan5(int currentElement)
        {
            return currentElement > 5;
        }



It is a simple method that returns whether or not the integer passed in is greater than 5.

We can now pass this to FindAll(), to match the elements in our list of integers that are greater than 5. Add this line to the Main() method:

IEnumerable<int> found = searcher.FindAll(new Predicate<int>(GreaterThan5));


‘found’ will contain all the elements greater than 5, as, remember, every int in the list is looped through and passed to our GreaterThan5 method (remember the call to searchFunction(element), of which calls the method encapsulated by the Predicate delegate. The encapsulated method in this case is GreaterThan5()).

If the method returns true, we know that element is greater than 5, and so we add it to the ‘matched’ collection to be returned.

Remember that we didn’t have to create an instance of our PerformAction delegate type to encapsulate a method back in the first section of this tutorial, we could use a shortcut. If you remember, we could just pass the name of the method to encapsulate, and all the instantiation of the delegate type would be handled for you.

That shortcut still applies here. Therefore, we can change the above line to:

IEnumerable<int> found = searcher.FindAll(GreaterThan5);


Note how by defining a delegate as a parameter, we are allowing our users to specify the algorithm for selecting elements. It is completely down to them.

As long as the method they pass into FindAll() returns a bool, and accepts the correct type of parameter (depends on the type of elements it is operating on due to generics), FindAll() is happy and will execute fine; thus meaning our user can define whatever algorithm they want in the body of the method to select elements.

Now that is flexibility!

However, I know what your thinking, do I really have to define an entirely new method (GreaterThan5()) just so I can pass it into FindAll(). It’s such a tiny method that will be passed to FindAll(), and it won’t get used again. That’s a bit wasteful isn’t it?

Fortunately, there are these things called anonymous methods that provide further syntactical shortcuts :).


Anonymous Methods

We don’t have to define a named method to pass into FindAll() in our previous example. We can define an unnamed method (anonymous method), and pass that into the method instead. For example, you could remove GreaterThan5() and do something like this when calling FindAll():

IEnumerable<int> found = searcher.FindAll(delegate(int currentElement) { return currentElement > 5; });



Now, note how we have defined the body of the method inside the FindAll parentheses. The method has no name, all you have to do is use the ‘delegate’ keyword, followed by the parameter list of the method (one int in this case), and then the body of the method.

That is an anonymous method, and means that you don’t have to explicitly define a named method that will likely not be used again.

It isn’t compulsory, but it is a very succinct and economical technique to use.

However, even that looks a bit cumbersome, doesn’t it? The use of the ‘delegate’ keyword, and parameter types all crammed into FindAll()’s argument list?

Enter lambdas...


Lambdas


What if I said that the previous line of code could be written as this:

IEnumerable<int> found = searcher.FindAll(currentElement => currentElement < 5);



A lambda is a very clean and concise anonymous method.

The general form of a lambda is:

Arguments to be passed => statements to process arguments

You can read ‘=>’ as ‘goes to’.

In the example, FindAll() can be thought to be expecting a method that takes a single integer as an argument, and returns a bool. The compiler knows that this is the kind of method that FindAll() is expecting, because it knows how the Predicate type is defined.

Therefore, technically, why should we have to explicitly declare the type of the parameter (int)? The compiler can work it out from the type of delegate that is being use to encapsulate the method.

The compiler infers the parameter and return types, using the method signature (and return type, as signature doesn't include return type) expected by the Predicate delegate.

So, with the lambda expression, FindAll() loops through each element in the list, passing each element to the lambda expression (via the ‘currentElement’ parameter). That parameter then gets processed in this statement:

currentElement > 5;



and returns the result as the compiler recognises that the lambda needs to return a bool in order to adhere to the contract set by the Predicate delegate type. The resulting bool is used in our FindAll method to determine whether or not that element should added to the collection of matched elements.

A lambda that has a single statement to process is called an expression lambda.

Lambdas can take multiple arguments (multiple arguments must be enclosed in parentheses however), and can process the arguments using multiple statements (multiple statements must be enclosed in curly braces however, and are called statement lambdas).

So, wherever a delegate instance is being asked for, and thus the type of return value and parameters can be inferred by the compiler, a lambda can be used as a shortcut for instantiating an instance of the delegate and passing in the method to encapsulate.

For example, going back to my very first example with this field of PerformAction type:

We could encapsulate the Add method in the delegate PerformAction using this syntax:

this.actions = (operand1, operand2) =>
            {
                //calculate sum total
                double total = operand1 + operand2;

                //print out sum total
                Console.WriteLine("Sum total is {0}", total);
            };




Similarly, we could add the method to the invocation list using the += operator instead of the = operator in the above example.

Also, note that in statement lambdas, we must use a ‘return’ statement to return the correct value explicitly if the method is supposed to have a non void return type.

This is because there are multiple statements in the body, so if there are multiple statements that evaluate to the return type, there is no way for the compiler to know which value you want to return, so you have to tell it explicitly what to return.

This obviously isn’t a problem with the single statement lambdas (or single statement anonymous methods. Even though I used a return statement in my anonymous method above (the one with the use of the ‘delegate’ keyword), I didn’t have to explicitly use the ‘return’ statement), as there is only one statement, and the compiler is intelligent enough to realise that if there is only one statement, that statement must be the one that yields the return value (providing it yields a value of the correct type of course).

Thus, we can omit the explicit ‘return’ statement.

Further, remember right back in the first example, I said that wherever a delegate instance is expected, a shortcut is available.

Well, now we know about anonymous methods and lambdas, we can shorten our code even further.


Using Anonymous Methods and Lambdas

For example, go back to the ‘Events’ section, and look at this line:

example.ActionPerformed += new EventHandler<EventArgs>(example_ActionPerformed);


An instance (implying the use of the ‘new’ keyword) of the generic EventHandler delegate is expected on the right hand side of the += operator.

Therefore, we can use our shortcut like this:

example.ActionPerformed += example_ActionPerformed;


,i.e. we just use the method name.

However, we now know that method names can actually be replaced with anonymous methods, so we could write it like this:

example.ActionPerformed += delegate(object sender, EventArgs e) { Console.WriteLine("The type of the object that raised this event is {0}", sender.GetType()); };


However, anonymous methods can be shortened to lambdas, so we can shorten it even further:

example.ActionPerformed += (sender,e) => Console.WriteLine("The type of the object that raised this event is {0}", sender.GetType());


The compiler is expecting a method with two arguments (object sender, EventArgs e), therefore, it can implicitly work out the types of ‘sender’ and ‘e’.


So, wherever an instance of a delegate type is expected, any one of these three shortcuts can be used!


NOTE: This type of shortcut isn't strictly universal. WPF's routed event model's AddHandler() method, for example, demands that you use the 'new' keyword to create a new delegate instance, and pass the method into that, rather than just passing in the method and having all the instantiation work done for you.

Generally speaking though, you can use these shortcuts :)


Other features of delegates


Combining Delegates

If we have two delegates that are the same type, we can combine them using the ‘+’ operator.

I think it is quickest to learn from a MSDN example here. Here is the example; I have added some of my own comments to it:

class TestClass
    {
        static void Hello(string s)
        {
            System.Console.WriteLine("  Hello, {0}!", s);
        }

        static void Goodbye(string s)
        {
            System.Console.WriteLine("  Goodbye, {0}!", s);
        }

        static void Main()
        {
            //create 4 new delegate instance fields, of type Del
            Del a, b, c, d;

            // Instantiate the delegate object a that references 
            // the method Hello:
            a = Hello;

            // Instantiate the delegate object b that references 
            // the method Goodbye:
            b = Goodbye;

            //at this point, a("A") would print out  " Hello, A!"
            //and b("B") would print out " Goodbye, B!"


            // The two delegates, a and b, are composed/combined to form c: 
            c = a + b;

            //c("C") would print  " Hello, C!", and then " Goodbye, C!".
            //The two methods encapsulated by 'a' and b' have been combined
            //into one delegate; 'c'.


            // Remove a from the composed delegate, leaving d, 
            // which calls only the method Goodbye:
            d = c - a;

            //d("D") would print out " Goodbye, D!". The method originally
            //encapsulated by 'a' has been taken from 'c', and the remaining
            //methods are held in a new delegate; 'd'.

            System.Console.WriteLine("Invoking delegate a:");
            a("A");
            System.Console.WriteLine("Invoking delegate b:");
            b("B");
            System.Console.WriteLine("Invoking delegate c:");
            c("C");
            System.Console.WriteLine("Invoking delegate d:");
            d("D");

            
            Console.ReadKey(true);
        }
    }




Here is the MSDN article on the subject:

Combining Delegates Article


Contra variance and Covariance

Covariance is essentially a form of polymorphism but with return types of delegates. If a delegate can encapsulate a method with a base class as a return type, the method you choose to encapsulate with the delegate doesn’t have to have the base class return type. It can have a return type of derived classes also.

So, for example, if Animal is the base class of Cat and Dog, and a delegate can encapsulate a method with a return type of Animal, we can not only encapsulate methods with a return type of Animal in the delegate, but we can also encapsulate methods with a return type of Cat or Dog! This is because Cat and Dog are derived from Animal. They are a kind of Animal.


Contravariance deals with parameters rather than return types. However, it works the other way around to covariance (hence, ‘contra’). Continuing with the example of Animal as the base class, and Cat and Dog as the derived classes… If a delegate can encapsulate a method that takes Cat as an argument, you can actually encapsulate a method that takes Animal as an argument instead!


Here is a good article on the subject:

Covariance and Contravariance Article


General Summary

So, to summarise,

  • Delegates encapsulate a single method or multiple methods. When the delegate is invoked, all encapsulated methods are called. Methods are invoked using method call syntax.

  • Events are just an important use for delegates (in .NET terminology, it is not really correct to say events ARE delegates, as we know the compiler adds a bunch of extra code around the underlying delegate to give us an event. Events are definitely built upon delegates, however). To subscribe to an event (to subscribe to perform actions when an event is fired; to listen for an event), we add methods to the delegates invocation list. Each method in the list is executed when we fired the event; which we do by invoking the delegate. It is advised that we use the ‘event’ keyword on delegate fields that are going to be used as events.

  • Anonymous methods and lambdas and two related shortcuts (lambdas being a shortened anonymous method) that can be used when an instance of a delegate is expected. Instead of instantiating the delegate, and passing in the method name, we can just use an anonymous method or lambda expression without directly instantiating the delegate type. The method that the anonymous method or lambda represents is encapsulated by a delegate instance automatically.



In Conclusion

So there we have it! I think people new to delegates see some of the shortcuts they offer without knowing the full way of doing things, and it confuses them.

Anyway, here are some links to the MSDN documentation for your reference:

Delegates

Events

Lambdas


Also, for more specific details on implementing events, and implementing your own EventArgs derived classes (instead of just pasing in EventArgs.Empty) to allow passing of data between classes with events, see this tutorial –

Quick and Easy Custom Events

It is advisable that whenever you want to pass data between classes, you at least consider events due to the decoupling and abstraction they can provide :).

See all the C# Learning Series tutorials here!

This post has been edited by CodingSup3rnatur@l-360: 06 February 2012 - 11:51 AM


Is This A Good Question/Topic? 13
  • +

Replies To: Delegates, Lambdas and Events

#2 DivideByZero  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 238
  • View blog
  • Posts: 551
  • Joined: 02-December 10

Posted 22 March 2011 - 04:50 PM

I already learn this stuff but I wanted to check this tutorial out anyway.
I'm glad I did! The explanation of what the compiler is doing behind the scenes REALLY helps as it made my understanding even better :)

I look forward to any other tutorials you have planned for the future.
Was This Post Helpful? 1
  • +
  • -

#3 CodingSup3rnatur@l-360  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 992
  • Posts: 972
  • Joined: 30-September 10

Posted 23 March 2011 - 01:33 PM

Thanks a lot for the feedback, and i'm really pleased you liked it! I was hoping that the 'behind the scenes' explanation would help people understand.

As I mentioned in the tutorial, the various syntactical shortcuts can make things seem very confusing, but if you build up an understanding of what is actually happening and understand how those shortcuts arise from their longer equivalents, the whole subject makes a hell of a lot more sense :)
Was This Post Helpful? 0
  • +
  • -

#4 CodingSup3rnatur@l-360  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 992
  • Posts: 972
  • Joined: 30-September 10

Posted 10 April 2011 - 01:45 PM

One small thing I forgot to mention was that there is another shortcut for subscribing to an event. For example, this:


example.ActionPerformed += delegate(object sender, EventArgs e) { Console.WriteLine("ActionPerformed Event Fired");};



can be written like this:

example.ActionPerformed += delegate { Console.WriteLine("ActionPerformed event Fired"};};[/


I.e. you can omit the parameters after the 'delegate' keyword as long as you don't use either of the parameters in the method body.

This shortcut can be used whenever a delegate instance is expected (as long as you don't use the paramters in the method body), not just with event subscriptions.

This shortcut is only available for anonymous methods; it isn't available for lambdas :)


Also, you may be wondering how you can unsubscribe anonymous methods from an event. Well, the you have to keep a reference to the method (store it in a variable), and use that to unsubscribe from the event.

Here is a post on the subject:

Unsubscribing Anonymous Methods

NOTE: The first answer is wrong as you cannot assign anonymous methods to implicitly typed variables :)


Also note that if you do any WinForms programming, all the controls fire events in response to certain actions (the Button class has, amongst many, a Click event which is fired every time the button is clicked). You can subscribe to these events and thus perform actions when they occur. You can subscribe to any event that is pre defined in the .NET framework and C# classes, and perform your own actions in reaction to them being fired :)

This post has been edited by CodingSup3rnatur@l-360: 10 April 2011 - 02:28 PM

Was This Post Helpful? 2
  • +
  • -

#5 BobRodes  Icon User is offline

  • Your Friendly Local Curmudgeon
  • member icon

Reputation: 574
  • View blog
  • Posts: 2,989
  • Joined: 19-May 09

Posted 30 June 2011 - 03:06 PM

CodingSup, excellent tutorial! I'd like to mention that I found a small typo in the first instance of your Add method: Console.WriteLine(“Sum total is {0}”, total); has the slanted quotation marks and should read Console.WriteLine("Sum total is {0}", total);. I only found this because I pasted the code into the IDE and it wouldn't recognize those characters as quote marks.
Was This Post Helpful? 1
  • +
  • -

#6 tsackey  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 48
  • Joined: 11-March 10

Posted 13 October 2011 - 07:10 AM

Awesome tutorial!!! I learned a lot, for instance i have worked with .Net events for a few months now and i never understood the need for the "event" keyword but,now i know thanks to you.
Was This Post Helpful? 0
  • +
  • -

#7 scolty  Icon User is offline

  • D.I.C Regular

Reputation: 3
  • View blog
  • Posts: 259
  • Joined: 27-April 11

Posted 30 December 2011 - 04:39 AM

i like your delegates example

note: edited my post as you answered my question further down in ur post.

This post has been edited by scolty: 30 December 2011 - 05:57 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1