Author avatar

Dániel Szabó

Anonymous Delegates for C#

Dániel Szabó

  • Dec 20, 2019
  • 8 Min read
  • 740 Views
  • Dec 20, 2019
  • 8 Min read
  • 740 Views
Languages Frameworks and Tools
C#

Introduction

This guide will cover 3 important features within C#: Lambda Expressions, Delegates and Anonymous Methods. The first goal is to clarify the concepts, then dig deeper into how they work by inspecting the situations in which a developer should choose one over the other. Then some example code will be displayed to demonstrate their purpose.

Delegates

Typically one or more arguments are passed to functions, or nothing at all. They usually return a result, a dataset and answer or perform specific operations with the data or context they have. You should use delegates when you would like to pass the function itself as a parameter. Let's examine what C# has to offer in the following situation.

Delegates have a skeleton syntax which we can customize.

1
<access modifier(s)> delegate <return type> <delegate name> (<parameter_1>,<parameter_2>, etc...)
csharp

When working with delegates as a general rule of thumb, you can point a delegate to any method that has the same return type and parameter list. The delegate itself is a reference type variable which holds a reference to a method. A common use case is to implement reactions to specific events, and call-back methods. They are instances of a class derived from the System.Delegate baseclass.

Let's create a delegate that references any method which has a two-string argument.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
using System;

delegate string StateReaction(string server, string state);

namespace delegation
{
    class Program
    {
        public static string LinuxServer(string name, string state)
        {
            if (state == "up")
                { return $"The server: {name} is in state: {state}, nothing to worry about!"; }
            else if (state == "down")
                { return $"The server: {name} is in state: {state}, Does it need to run?"; }
            else
                { return $"The server: {name} is in state: {state}, definitely worth a check!"; }
        }
        public static string WindowsServer(string name, string state)
        {
            return $"The server: {name} is in state: {state}";
        }
        static void Main(string[] args)
        {
            StateReaction lin = new StateReaction(LinuxServer);
            StateReaction win = new StateReaction(WindowsServer);
            Console.WriteLine(lin("BIND", "up"));
            Console.WriteLine(lin("LDAP", "down"));
            Console.WriteLine(lin("Management", "unknown"));
            Console.WriteLine(win("Domain Controller", "down"));
            Console.ReadKey();
        }
    }
}
csharp

The execution looks something like this.

1
2
3
4
The server: BIND is in state: up, nothing to worry about!
The server: LDAP is in state: down, Does it need to run?
The server: Management is in state: unknown, definitely worth a check!
The server: Domain Controller is in state: down
bash

Basically you could further extend the functionality of this app with remote checking or ticket opening. The idea is to create a reaction to different states in case of linux and windows systems. The delegates help us separate the two platforms and allow us to implement custom checks for the devices based on their states.

There is another concept in the delegate realm calles Multicasting which means we can compose new delegates from other delegates with the + operator. The composed one calls the delegates it was composed from, but the rule is that you can compose two delegates if they are of the same type. The - operator allows you to remove delegates from the composition.

Anonymous methods

As mentioned, delegates are reference types and are used to reference any method that has the same signature. In contrast to them, the anonymous functions are all about passing code block or code as a delegate parameter. Sometimes they are referred to as "anonymous delegates" too. The return type of the anonymous function is inferred by the compiler by the return statement of the body. To put it simply, they allow the user to create an inline method that can also take parameters. The important thing to keep in mind is the usage of the delegate keyword when you define one.

Let's demonstrate it with a small code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;

namespace delegationanonym
{
    class Program
    {
        public delegate void State(string state);
        static void Main(string[] args)
        {
            int outsideScope = 99;
            State s = delegate (string state) {
                Console.WriteLine($"The state: {state} was entered!");
                Console.WriteLine($"The value from outer scope is: {outsideScope}");
            };
            s("up");
            Console.ReadKey();
        }
    }
}
csharp

The output of the code looks like this.

1
2
The state: up was entered!
The value from outer scope is: 99
bash

Here we can see an inline delegate in action. This allows us to delegate objects without creating additional methods. Note how the variable from the outer scope is still accessible to the anonymous function. You are able to pass a method which can take delegates as parameters.

Lambda expressions

A Lambda expression is an anonymous function that can contain expressions and statements. They are also used to create delegates or expression tree types. Expressions can be mystifying, but simply put, they are nothing more than code represented as data and objects in a .NET application.

According to Jon Skeet, "Expression trees are a way of expressing logic so that other code can interrogate it."

When the Lambda expression is converted into an expression tree, the compiler does not create the Intermediate Language for it. The compiler only creates the Intermediate Language which will build the expression tree that represents the same logic.

In a sense, Lambda expressions are a replacement for the anonymous methods, as they add many features.

There are two very important concepts, one is using braces with Lambda expressions and the other is not using them. When you create Lambda expression with braces you create something referred to as statement lambda. Not using braces creates expression lambda.

Expression Lambda has the following syntax.

1
(input-parameters) => expression
csharp

Statement lambda has the following syntax.

1
(input-parameters) => { expression ; expression ; expression ;}
csharp

Let's demonstrate them with a small example code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;

namespace lambd
{
    class Program
    {
        static void Main(string[] args)
        {
            Func<string,string> Welcome = name => 
            {
                return $"Welcome {name} to the Written Guides!";
            };
            Func<int, int> enTriple = x => x*3;
            Console.WriteLine($" 3 x 5 = {enTriple(5)}");
            Console.WriteLine(Welcome("Daniel"));
            Console.ReadKey();
        }
    }
}
csharp

The output of the app is as follows.

1
2
 3 x 5 = 15
Welcome Daniel to the Written Guides!
bash

The first output comes from the expression lambda style definition, and the other comes from the statement lambda style definition.

Conclusion

This guide aims to clarify the topic of the Lambda expressions, Anonymous methods and Delegates. By demonstrating the features with sample apps or small codes if you will, you should be able to accelerate your development and make it more C#-ish. I hope this has been informative for you and I hope you have found what you were looking for. If you liked this guide give it a thumbs up and stay tuned for more.

10