C# Delegates Simplified — Part 2
Tags: csharp, dotnet, dotnetcore, programming
Published: 2023-09-14 05:23:31

_This article is the second one of a series of 3 articles on C# delegates. If you haven’t gone through the [part 1](https://dev.to/ravisankarrao/c-delegates-simplified-part-1-5bnf), I suggest you to go through it first._

In the [previous article](https://dev.to/ravisankarrao/c-delegates-simplified-part-1-5bnf) we went through a brief intro on what delegates are, how are they declared, initialized and invoked. Here we will take a simple use case where delegates can be useful.

One thing which the previous article did not mention is that, we use delegates majorly to pass functions as parameters. We will work on this usage here.

We have a Person class with FirstName and LastName as its member properties. The requirement is to get a person’s name in different formats. For one of the case, we have overridden [ToString](https://learn.microsoft.com/en-us/dotnet/api/system.object.tostring?view=netcore-3.1#the-default-objecttostring-method) as below.

```
public class Person
{
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public override string ToString()
        {
            return $"{this.FirstName} {this.LastName}";
        }
}
```

I created a small WPF application to demonstrate this. Screenshot of the UI is below. It has a set of radio buttons to select a format, then on click of “Display Name” button, names should be displayed within the list box on the right as per the selected format radio button.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kk5jk621gz19j84dg8ru.png)

Coming back to our Person class. In order for the class to support different formats of name, one way we can achieve this is by creating a parameterized _ToString_ method in the class, send some kind of _enum_ to decide in which format we need to return, add a switch case, construct that format and return the formatted name. Below is how this can be done.

```
public enum FormatType
{
        Default = 1,
        LastNameFirst,
        LastNameOnly,
        FirstNameOnly,
        InitialsOnly
}

public class Person
{
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public override string ToString()
        {
            return $"{this.FirstName} {this.LastName}";
        }

        public string ToString(FormatType format)
        {
            switch (format)
            {
                case FormatType.Default:
                    return this.ToString();
                case FormatType.LastNameFirst:
                    return $"{this.LastName} {this.FirstName}";
                case FormatType.LastNameOnly:
                    return this.LastName;
                case FormatType.FirstNameOnly:
                    return this.FirstName;
            }
            return default;
        }
}
```
Though above design would work fine but there is a problem with that. Every time we need a new format to be added, we need modify Person’s _ToString_ method to add one more case for a new format type.

This goes against the **Open-Close** principle of SOLID design which states that a software entity (Person class in this case) should be open for extension but closed for modification.

This also goes against **Single Responsibility** principle of SOLID which states an entity should have responsibility for a single part of the program. In this case the responsibility of Person class should only be of holding the data, and not what to do with this data.

We can address both the issues using delegates

Below is a modified Person class that uses a _ToString_ method that takes a delegate as a parameter and returns a string. We invoke the delegate inside this method and return its result, in this case it being string.

```
public delegate string PersonFormatter(Person persion);
public class Person
{
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string ToString(PersonFormatter formatter)
        {
            return formatter(this);
        }
}
```

We can see how the Person class is now lean and does not do anything apart from storing information.

We create a _NameFormatter_ class with different methods to format the name. This was we keep the name formatting code separate from Person class. It has four methods as per the radio buttons in our WPF UI.

```
public static class NameFormatter
{
        public static string Default(Person person)
        {
            return $"{person.FirstName} {person.LastName}";
        }
        public static string LastNameFirst(Person person)
        {
            return $"{person.LastName} {person.FirstName}";
        }
        public static string FirstNameOnly(Person person)
        {
            return person.FirstName;
        }
        public static string LastNameOnly(Person person)
        {
            return person.LastName;
        }
}
```
Remember the WPF app screenshot above ? In the code behind file, we have the following

- List of persons which is dummy data — people

- Local variable of type _PersonFormatter_ delegate — formatter

- Function which assigns the above formatter variable based on which radio button is selected.


```
List<Person> people = new List<Person>
{
            new Person { FirstName = "John", LastName = "Doe" },
            new Person { FirstName = "Tony", LastName = "Stark" }
};

public PersonFormatter formatter;

public void AssignFormatter()
{
            if (rdBtn_Default.IsChecked.Value)
                formatter = NameFormatter.Default;
            else if (rdBtn_LastNameFirst.IsChecked.Value)
                formatter = NameFormatter.LastNameFirst;
            else if (rdBtn_FirstNameOnly.IsChecked.Value)
                formatter = NameFormatter.FirstNameOnly;
            else if (rdBtn_LastNameOnly.IsChecked.Value)
                formatter = NameFormatter.LastNameOnly;
}
```
On click of the “Display Names” button, below function is invoked.

```
private void DisplayName_Click(object sender, RoutedEventArgs e)
{
            namesList.Items.Clear();   // clearing list box
            AssignFormatter();        // based on radio button  
            foreach (var person in people)
                namesList.Items.Add(person.ToString(formatter));
}
```

- We clear all items from the _listbox_ named as _namesList_

- _AssignFormatter_ function is invoked which assigns the type of formatter function to be assigned to our delegate variable formatter.

- We iterate through people, and for each of the item we call it’s _ToString_ method and pass our delegate formatter. If you remember, we had a _ToString_ method which takes [PersonFormatter](url) delegate as a parameter

```
public string ToString(PersonFormatter formatter)
{
       return formatter(this);
}
```
Here the formatter is invoked which in turn invokes which ever NameFormatter function was assigned earlier in the AssignFormatter based on selected radio button. The result is returned as string.

This example is a fairly simple use of delegates but gives more of an idea how they are useful to follow SOLID design principles.

In the next article we discuss how delegates are related to lambda expressions.