7. Delegates, Events, and Lambda Expressions

About this Tutorial

Objectives

Delegates will learn to develop applications using C# 4.5. After completing this course, delegates will be able to:

  • Use Visual Studio 2012 effectively
  • Create commercial C# Web Applications
  • Develop multi-threaded applications, Use WCF and LINQ

Audience

This course has been designed primarily for programmers new to the .Net development platform. Delegates experience solely in Windows application development or earlier versions of C# will also find the content beneficial.

Prerequisites

No previous experience in C# programming is required. But any experience you do have in programming will help. Also no experience in Visual Studio is required. But again any experience you do have with programming development environments will be a valuable.

Download Solutions

HTML tutorial


Overview

In this tutorial you will be learning about single-cast delegates and multicast delegates that allow much greater functionality to the programmer by allowing one instance but many possible methods. You will also be learning about how to create anonymous methods which effectively are delegates but with a body and parameters. Next will be lambda expressions which allow the programmer you to easily write these anonymous methods in a one line statement. After this will be working on using events which you have most likely used before.

Estimated Time – 1 Hour

Not what you are looking? Try the next tutorial – Generics

Lab 1: Delegates

Lab 1: Delegates

Overview

  1. A delegate is a .NET data type that acts as a
    type-safe pointer
    to a method on an object/class:

    • A delegate specifies the signature of methods you would like to call through the delegate, e.g.
      delegate double TrigOp(double radians);
    • In your client code, create a delegate instance and bind it to any method (on any object/class) that has the correct signature
      TrigOp op = new TrigOp(Math.Sin);
    • In your client code, you can use the delegate to call the method when you’re ready –
      double result = op(an-angle-in-radians);
Lab
  1. Open visual studio, Create a New Project>C#>Windows>Form Application and call this TrigDelegates, this is going to use delegates to allow us to write only one main method easily instead of having a large multi layered if statement. What this is going to work is what the value of a trigonometric angle is –
  2. Form

  3. Then you need to create a windows form that looks similarly to what is below – name the buttons btnSin, btnCos, btnTan and txtDegrees –
    TrigForm
  4. Add this code to Form1.cs – We create a delegate that will be able to hold any method that accepts a double as its input. In this case it will be either Sin, Cos or Tan. To start we well create the event handlers for when the buttons are pressed –
    delegate double TrigOp(double radians);
     private void btnSin_Click(object sender, EventArgs e)
     {
      TrigOp op = new TrigOp(Math.Sin);
      MyPerformOp(op);
      // You can also not mention the delegate object at all....
      // MyPerformOp(Math.Sin);
     }
     private void btnCos_Click(object sender, EventArgs e)
     ...
     }
  5. View code file.
  6. Now lets create our logic to actually work out the maths behind our program –
    // Perform the operation indicated by "op"
    private void MyPerformOp(TrigOp op)
    {
     // Test if the text box is empty
     if (this.txtDegrees.Text.Length == 0)
     {
      // Display error message
      MessageBox.Show(
      ...
     }
     // Get the angle entered in the text field
     double degrees = 0.0;
     try
     {
      degrees = double.Parse(this.txtDegrees.Text);
     }
     catch (FormatException)
     {
      MessageBox.Show(
      ....
     }
     // Convert the angle from degrees into radians
     double radians = (degrees / 360) * 2 * Math.PI;
     //*******************
     // Invoke function specified by the "op" delegate
     double result = op(radians);
     ...
    }
  7. View code file.
  8. Now you have finished feel free to run the application and test its functionality; maybe
  9. .NET supports two distinct kinds of delegate:
    • Single-cast delegates.
    • Multicast delegates.
  10. Why use multicast delegates?
    • If you need to perform a series of operations on the same object.
    • If you need to perform an operation on a series of different objects.
  11. Example Of a Multi Cast delegate:
    • Let’s see an example of how to define and use multicast delegates – See the MulticastDelegates demo project.
    • The sample has a main form, which allows the user to create child forms – The user can then change the colour of the child forms and it uses a multicast delegate to invoke a Repaint() method on each child form
    • The main difference with this is we create a list of delegates that are all linked to the repaint method allowing us to repaint all the children windows on one button click –
      // Create a new delegate for the child form's Repaint method.
      MyDelegate newDelegate = aChildForm.Repaint;
      // If multicast delegate is null, this is the first child form.
      if (mTheDelegate == null)
      {
       // Use new delegate as the basis for the multicast delegate.
       mTheDelegate = newDelegate;
       sbStatus.Text = "Created first child form.";
      }
      else
      {
       // Combine new delegate into the multicast delegate.
       // Equivalent to: mTheDelegate = Delegate.Combine(mTheDelegate, newDelegate);
       mTheDelegate += newDelegate;
       // Use multicast delegate to count the child forms.
       sbStatus.Text = "Created child form " + mTheDelegate.GetInvocationList().Length + ".";
      }
    • View code file.
    • MultiCastDelegates

Lab 2: Anonymous Methods and Lambdas

Lab 2: Anonymous Methods and Lambdas

Overview

  1. An anonymous method is a method with no name – The method just has parameters and a return type.
  2. Anonymous methods are used with delegates – Assign an anonymous method to a delegate variable.
  3. To call anonymous methods:
    • You must call anonymous methods through a delegate.
    • You cannot call anonymous methods directly – Internally, the compiler converts anonymous methods into named methods in IL code.
  4. lamdaexp

  5. Outer Variables:
    • An anonymous method can access variables declared in the outer scope – These are called “outer variables”.
    • When an outer variable is referenced by an anonymous method, the outer variable is said to be “captured” – The outer variable will not be garbage collected until all delegates referencing the anonymous method become eligible for garbage collection
    • Consider this example –
      • MyMethod declares a local variable, myLocalVar.
      • MyMethod returns anonymous method (via a delegate).
      • Outside world can call anonymous method via delegate –
        public delegate int MyDelType(); AnonMethodsOuterVariablesDemo.cs
        public class MyClass
        {
         public static MyDelType MyMethod()
         {
          int myLocalVar = 0;
          return delegate { return ++myLocalVar; };
         }
        }
        MyDelType d = MyClass.MyMethod();
         Console.WriteLine(d());
         Console.WriteLine(d());
      • View code file.
  6. Lambda Expressions:
    • A lambda expression is a simplified syntax for anonymous methods.
    • Here is the formal syntax for a lambda expression
      (comma-separated-method-params) => method-body
  7. Some Examples:
    • Here’s a delegate type that has no parameters
      delegate void MyHandlerNoParams();
      MyHandlerNoParams del1 = () => Console.WriteLine("Hello single-line lambda!");
      MyHandlerNoParams del2 = () =>
      {
       Console.WriteLine("Hello multi-line lambda!");
       Console.WriteLine("Goodbye multi-line lambda!");
      };
    • View code file.
    • Here’s a delegate type that takes a single parameter
      delegate void MyHandlerOneParam(int i);
       MyHandlerOneParam del1 = i => Console.WriteLine("Via del1, value is {0}.", i);
      MyHandlerOneParam del2 = (i) => Console.WriteLine("Via del2, value is {0}.", i);
       MyHandlerOneParam del3 = (int i) => Console.WriteLine("Via del3, value is {0}.", i);
    • View code file.

Lab 3: Events

Lab 3: Events

Overview

  1. .NET supports events:
    • Familiar to most developers.
    • But different in .NET
  2. Events are based heavily on delegates:
    • .NET events encapsulate the task of adding event receivers
    • Also encapsulate the task of notifying event receivers when an event is raised.
  3. Events

Lab
  1. How to Define and Use Events – Steps to Take:
    • Define an event argument’ class, to hold context information when an event is raised.
    • Define a delegate type, to specify the signature of the event (i.e. event handlers must have this signature).
    • In your event-source class, publish events using the event keyword.
    • In the event-source class, raise events when something interesting happens.
    • In the client code, subscribe to the events you’re interested in – Provide event-handler methods, these event-handler methods will be called when the event is raised.
  1. We are now going to create a bank account that enables the user to deposit and withdraw money using lamdas and events.
  2. Open Visual Studio; New Project>C#>Windows>Console Application and create a console application with the name BankSystem
  3. BankSystemForm

  4. To start lets create a new class called BankAccount and in this class add our business logic, Some constructors for our class and some events. First in the new class we will create the a transaction event that can be called from another class to return the transaction details. It will create a new transaction each time its called and has an Override for ToString() to return the information to the user –
    public class BankAccountEventArgs : EventArgs
    {
     private double transactionAmount;
     private DateTime timestamp;
     public BankAccountEventArgs(double transactionAmount)
     {
      this.transactionAmount = transactionAmount;
      timestamp = DateTime.Now;
     }
     public override string ToString()
     {
      return string.Format("Transaction amount {0}, timestamp {1}", transactionAmount, timestamp);
     }
    }
  5. View code file.
  6. Now to add to the same class BankAccount is our BankAccount constructors etc… This will contain one constructor to create our bank account and then we will have three methods. One to withdraw, one to deposit money and the other is a ToString() override. We also create two events one to handle being overdrawn and one to a protection limit which can be raised in our two methods using money –
    public class BankAccount
     {
      // Fields.
      private string accountHolder;
      private double balance;
      // Events.
      public event EventHandler<BankAccountEventArgs> ProtectionLimitExceeded;
      public event EventHandler<BankAccountEventArgs> Overdrawn;
      // Methods etc.
      public BankAccount(string accountHolder)
      {
       this.accountHolder = accountHolder;
       this.balance = 0;
      }
  7. Now adding the methods for deposit and withdraw with a ToString() method in there as well so we can display our information in a customized manner.
      public void Deposit(double amount)
      {
       balance += amount;
       
       // If balance has exceeded the government's protection limit, raise a ProtectionLimitExceeded event.
       if (balance >= 50000 && ProtectionLimitExceeded != null)
       {
        ProtectionLimitExceeded(this, new BankAccountEventArgs(amount));
       }
      }
      public void Withdraw(double amount)
      ...
     }
  8. View code file.
  9. Now the class has been created we will add the code to the Program.cs to show it working in action. What will happen is we are setting up three different methods to handle either an overdrawn event or protection limit event and will raise an event to show these in action. First of all create a new account –
    BankAccount acc1 = new BankAccount("Brendan");
  10. Then we will create our first way to deal with the events. This is using normal event handlers to start –
    // Handle events using verbose (or shorthand) syntax.
    acc1.ProtectionLimitExceeded += new EventHandler<BankAccountEventArgs>(My_ProtectionLimitExceeded_Handler);
    acc1.Overdrawn += My_Overdrawn_Handler;
    // AND THE METHODS TO DEAL WITH THEM
    static void My_ProtectionLimitExceeded_Handler(object sender, BankAccountEventArgs e)
     {
      Console.WriteLine("ProtectionLimitExceeded handler method, eventargs {0}.", e);
     }
     static void My_Overdrawn_Handler(object sender, BankAccountEventArgs e)
     {
      Console.WriteLine("Overdrawn handler method, eventargs {0}.", e);
     }
  11. View code file.
  12. The second way is to use the anonymous methods that we learnt about in lab two. All of these methods for all three ways are all referencing the BankAccountEventArgs that was created when we made the BankAccountEventArgs class and are getting their data using the overriding ToString() method –

    // Handle events using anonymous methods.
    acc1.ProtectionLimitExceeded += delegate(object sender, BankAccountEventArgs e)
     {
      Console.WriteLine("ProtectionLimitExceeded anon method, eventargs {0}.", e);
     };
     acc1.Overdrawn += delegate(object sender, BankAccountEventArgs e)
     {
      Console.WriteLine("Overdrawn anon method, eventargs {0}.", e);
     };
  13. View code file.
  14. For our last way of handling an event we will use lambda expressions as learnt about in lab two –
    // Handle events using lambda expressions.
    acc1.ProtectionLimitExceeded += (sender, e) => Console.WriteLine("ProtectionLimitExceeded lambda, eventargs {0}.", e);
    acc1.Overdrawn += (sender, e) => Console.WriteLine("Overdrawn lambda, eventargs {0}.", e);
  15. when we run the application we will get 3 different event handlers occurring from the one event –
    // Do some stuff.
     acc1.Deposit(10000);
     acc1.Deposit(30000);
     acc1.Deposit(40000);
     acc1.Withdraw(1000000);
    Console.ReadLine();
  16. View code file.
  17. App

 

Well done. You have completed the tutorial in the C# course. The next tutorial is

8. Generics


Back to beginning
Copyright © 2016 TalkIT®






If you liked this post, please comment with your suggestions to help others.
If you would like to see more content like this in the future, please fill-in our quick survey.
Scroll to Top