C# Delegates

Leave a comment

Delegates in C# hold a reference to a method. If you think about writing methods, you may generally send parameters such as objects/type variables to the method. At times, you may want to send an actual method as a parameter to another method. Delegates are like a placeholder for methods.

Let’s go through an example.

Let’s say we have a list of customers that are based on different cities.

 Customer c1 = new Customer() { FirstName = "John", LastName = "Smith", City = "New York" };
 Customer c2 = new Customer() { FirstName = "James", LastName = "Smith", City = "Los Angeles" };
 Customer c3 = new Customer() { FirstName = "Bob", LastName = "Smith", City = "Los Angeles" };
 Customer c4 = new Customer() { FirstName = "John", LastName = "Johnson", City = "New York" };
 Customer c5 = new Customer() { FirstName = "Bob", LastName = "Jackson", City = "New York" };
 List<Customer> customers = new List<Customer>() { c1, c2, c3, c4, c5 };

Now, let’s say we want to print a list of each of customers that are based in New York, and based on Los Angeles. We also want to print a list of customers with the last name “Smith”. To do this, we could use the code below, which is a procedure that takes a list of customers and checks for each condition:

        static void PrintCustomers(List customers)
        {
            Console.WriteLine("Los Angeles");
            foreach (Customer c in customers)
            {
                if (c.City == "Los Angeles")
                {
                    Console.WriteLine("{0}, {1}, {2}", c.FirstName, c.LastName, c.City);
                }
            }
            Console.WriteLine();

            Console.WriteLine("New York");
            foreach (Customer c in customers)
            {
                if (c.City == "New York")
                {
                    Console.WriteLine("{0}, {1}, {2}", c.FirstName, c.LastName, c.City);
                }
            }
            Console.WriteLine();

            Console.WriteLine("Smiths");
            foreach (Customer c in customers)
            {
                if (c.LastName == "Smith")
                {
                    Console.WriteLine("{0}, {1}, {2}", c.FirstName, c.LastName, c.City);
                }
            }
            Console.WriteLine();
        }

This produces:

Now, if we wanted to add a list of customers in different cities, we would need to extend our procedure itself by adding a new check. This makes the procedure itself less scalable.

We can rewrite our procedure, so that we can pass a condition to it and have the procedure return what we want to print.

The first thing to do is to define a delegate. What we are saying here, is we have a delegate method called DoFilter, which is expecting a Customer as a parameter. This is the signature of the delegate. When we use this, it will require the same paramters:

 public delegate bool DoFilter(Customer c);

Now that we have defined the delegate, we can write functions with the same signature. In our example, we will be returing a boolean if the city is “New York” and “Los Angeles”. We also want to know if a customer is “Smith”. So, we can create 3 separate functions that we will be passing to our main function as delegates:

        static bool CityIsNewYork(Customer c)
        {
            return c.City == "New York";
        }

        static bool CityIsLosAngeles(Customer c)
        {
            return c.City == "Los Angeles";
        }

        static bool CustomerIsSmith(Customer c)
        {
            return c.LastName == "Smith";
        }

Next, we will rewrite our main function. Instead of just passing a list of customers, we will also pass our DoFilter delegate. This will be substituted for one of the functions we wrote above, such as CityIsNewYork. We are also adding a “title” parameter for readability to print to the console:

 static void PrintCustomer(string title, List<Customer> customers, DoFilter filter)
 {
   Console.WriteLine(title);
   foreach (Customer c in customers)
   {
    if (filter(c))
    {
      Console.WriteLine("{0}, {1}, {2}", c.FirstName, c.LastName, c.City);
    }
   }
  Console.WriteLine();
 }

Finally, we call our new PrintCustomer function, like below. As can be seen, the delegate function CityIsLosAngeles is passed as a parameter to our PrintCustomerMethod:

PrintCustomer("Los Angeles:", customers, CityIsLosAngeles);
PrintCustomer("New York:", customers, CityIsNewYork);
PrintCustomer("Smiths:", customers, CustomerIsSmith);

When running this, we get:

This is the same result as our original function. However, using delegates the code is now cleaner and extendable. If we now wanted to print all customers living in Philadelphia, we could simply create a new function and call it as a delegate.

Delegates are often used in event handlers, for example when a button is clicked, pass a delegate function to perform an action:

Button1.Click += new EventHandler(OnClickEvent);

Full code from the example above:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Carl.Delegates
{
    public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string City { get; set; }
    }
    class Program
    {
        public delegate bool DoFilter(Customer c);

        static void Main(string[] args)
        {
            Customer c1 = new Customer() { FirstName = "John", LastName = "Smith", City = "New York" };
            Customer c2 = new Customer() { FirstName = "James", LastName = "Smith", City = "Los Angeles" };
            Customer c3 = new Customer() { FirstName = "Bob", LastName = "Smith", City = "Los Angeles" };
            Customer c4 = new Customer() { FirstName = "John", LastName = "Johnson", City = "New York" };
            Customer c5 = new Customer() { FirstName = "Bob", LastName = "Jackson", City = "New York" };
            List customers = new List() { c1, c2, c3, c4, c5 };

            //PrintCustomers(customers);
            PrintCustomer("Los Angeles:", customers, CityIsLosAngeles);
            PrintCustomer("New York:", customers, CityIsNewYork);
            PrintCustomer("Smiths:", customers, CustomerIsSmith);
            Console.Read();
        }

        static void PrintCustomers(List customers)
        {
            Console.WriteLine("Los Angeles");
            foreach (Customer c in customers)
            {
                if (c.City == "Los Angeles")
                {
                    Console.WriteLine("{0}, {1}, {2}", c.FirstName, c.LastName, c.City);
                }
            }
            Console.WriteLine();

            Console.WriteLine("New York");
            foreach (Customer c in customers)
            {
                if (c.City == "New York")
                {
                    Console.WriteLine("{0}, {1}, {2}", c.FirstName, c.LastName, c.City);
                }
            }
            Console.WriteLine();

            Console.WriteLine("Smiths");
            foreach (Customer c in customers)
            {
                if (c.LastName == "Smith")
                {
                    Console.WriteLine("{0}, {1}, {2}", c.FirstName, c.LastName, c.City);
                }
            }
            Console.WriteLine();
        }


        static void PrintCustomer(string title, List customers, DoFilter filter)
        {
            Console.WriteLine(title);
            foreach (Customer c in customers)
            {
                if (filter(c))
                {
                    Console.WriteLine("{0}, {1}, {2}", c.FirstName, c.LastName, c.City);
                }
            }
            Console.WriteLine();
        }

        static bool CityIsNewYork(Customer c)
        {
            return c.City == "New York";
        }

        static bool CityIsLosAngeles(Customer c)
        {
            return c.City == "Los Angeles";
        }

        static bool CustomerIsSmith(Customer c)
        {
            return c.LastName == "Smith";
        }
    }
}

 

THANKS FOR READING. BEFORE YOU LEAVE, I NEED YOUR HELP.
 

I AM SPENDING MORE TIME THESE DAYS CREATING YOUTUBE VIDEOS TO HELP PEOPLE LEARN THE MICROSOFT POWER PLATFORM.

IF YOU WOULD LIKE TO SEE HOW I BUILD APPS, OR FIND SOMETHING USEFUL READING MY BLOG, I WOULD REALLY APPRECIATE YOU SUBSCRIBING TO MY YOUTUBE CHANNEL.

THANK YOU, AND LET'S KEEP LEARNING TOGETHER.

CARL

https://www.youtube.com/carldesouza

 

ABOUT CARL DE SOUZA

Carl de Souza is a developer and architect focusing on Microsoft Dynamics 365, Power BI, Azure, and AI.

carldesouza.comLinkedIn Twitter | YouTube

 

See more articles on: C#

Leave a Reply

Your email address will not be published. Required fields are marked *