Anonymous functions

April 2, 2016
anonymous functions LINQ lambda expressions C# development .NET

The difference between a normal function and an anonymous one

Let’s start with comparing an anonymous function written with a lambda expression to a named method, a normal conventional function.

Consider this example:

string foundPerson = people.Find(person => person.Contains("Joe"));

versus

public string FindPerson(string nameContains, List<string> persons)
{
    foreach (string person in persons)
        if (person.Contains(nameContains))
            return person;
    return null;
}

These are functionally equalivalant. Performance is also equal.

With anonymous functions however you don’t need to hazzle with declaring variables or names of a method, in this case FindPerson and person.

Simply write a function inline without it even having a name. Hence it is called anonymous.

Lambda expression vs delegate

In the past anonymous functions could only be written using delegates in C#. As of C# 3 lambda expressions where included in the language depicted with => and they have almost completely replaced anonymous methods. Anonymous functions written with a lambda expressions can obtain the same logic but with less steps than if delegates where used. Anonymous methods can be spotted whenever you see the delegate keyword.

Delegate Evolution

  • In C# 1.0 you create a delegate instance and initialize with a method reference.
  • C# 2.0 introduced Anonymous methods that can be executed with delegate invocation.
  • Then in C# 3.0, lambda expressions are similar in concept to anonymous methods but more expressive and conches.

Let’s have a look at a delegate example. This delegate called MyDelegate can reference all methods that have one string as an input and that returns one string.

using System;

//Declare a delegate 
delegate string MyDelegate (string s);

namespace Rextester
{
    class Program
    {
        //Declare methods with the signature of the delegate
        public static string TestMethod(string str)
        {         
            return "Hello " + str;
        }

        public static string TestMethod2(string str)
        {         
            return "Hello again " + str;
        }

        public static void Main(string[] args)
        {
            // Now we instanciate methods that the delegate can refer to with delegate objects
            MyDelegate ps1 = new MyDelegate(TestMethod);
            MyDelegate ps2 = new MyDelegate(TestMethod2);

            // Calling the methods using the delegate objects ps1 and ps2:    
            Console.WriteLine(ps1("Peter"));
            Console.WriteLine(ps2("Michael"));         
        }
    }
}

output:

        Hello Peter
        Hello again Michael

C# delegates are the same as passing methods to another method.

So there are two kinds of anonymous functions:

  • Anonymous method
  • Lambda expression

It’s easy to confuse the term anonymous function and anonymous method. Lambda expressions and anonymous methods are collectively called anonymous functions.

Anonymous functions are useful for one-off methods that don’t benifit from the extra work required to create a full method.

Storing Anonymous functions with Func

Func is used to encapsulate a delegate function. By doing this we get a higher-order procedure that can be passed around as an object. A Func can have several input parameters. Here is an example of a Func written with a lambda expression:

Func<int, bool> myFunc = x => x == 5;
bool result = myFunc(4); // returns false
Console.WriteLine(result);

The func is declared with the first argument the input type and the last argument the output type.

Func<int, int, bool> myFunc = (x,y) => x + y == 5;  
bool result = myFunc(4,1); // returns true
Console.WriteLine(result);

In this case we have two input arguments of int. The last argument in the func allways shows the output type.

Same as above can also be written with an anonymous method:

Func<int, bool> myFunc = delegate (int x) { return x == 5; };
bool result = myFunc(4); // returns false
Console.WriteLine(result);

There are also Func that takes an expression as input:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };  
int bigNumbers = numbers.Count(n => n > 5);
Console.WriteLine(bigNumbers);

output: 4

This counts all elements in the list that are bigger than 5.

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6); 
firstNumbersLessThan6.ToList().ForEach(Console.WriteLine);

output: 5 4 1 3

Takes all the numbers left of the element bigger than 6.

var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
firstSmallNumbers.ToList().ForEach(Console.WriteLine);

output: 5 4

First numbers bigger than its index.

This click event using an anonymous method

button.Click += delegate (object sender, EventArgs e) {
    // Event code here
};

Can be written with lambda expression as

button.Click += (s, i) =>
{
    // Event code here
}

Some examples of normal functions rewritten to an anonymous one

Some typically usefull ones

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> values = new List<int>() { 1, 1, 1, 2, 3 };

        // Multiple statements in an anonymous method.
        List<int> res = values.FindAll(delegate(int element)
        {
            if (element > 10)
            {
                throw new ArgumentException("element");
            }
            if (element == 8)
            {
                throw new ArgumentException("element");
            }
            return element > 1;
        });

        // Display results.
        foreach (int val in res)
        {
            Console.WriteLine(val);
        }
    }
}

Output

2
3

Can be rewritten with lambda expressions:

List<int> values = new List<int>() { 1, 1, 1, 2, 3 };

// Multiple statements in a lambda expression.
List<int> res = values.FindAll(element =>
{
    if (element > 10)
    {
        throw new ArgumentException("element");
    }
    if (element == 8)
    {
        throw new ArgumentException("element");
    }
    return element > 1;
});

// Display results.
res.ToList().ForEach(Console.WriteLine);

Output

2
3

A variation of this would have been to use Find instead of FindAll. Then we would only get the first element larger than 1. Output would have been 2. Or if we would use FindLast we would search for the first element starting backwards and gotten 3.

Action delegates

Action delegate is the same a func delegate except that it has no return value.

static void ConsolePrint(int i)
{
    Console.WriteLine(i);
}

static void Main(string[] args)
{
    Action<int> printActionDel = ConsolePrint;
    printActionDel(10);
}

ConsolePrint was encapsulated and stored in the Action printActionDel.

Or why not do it with a lambda expression

Action<int> printActionDel = i => Console.WriteLine(i);       
printActionDel(10);
comments powered by Disqus