CodeGym /Courses /C# SELF /Introduction to anonymous methods (

Introduction to anonymous methods ( delegate)

C# SELF
Level 49 , Lesson 0
Available

1. Introduction

When you're programming, sometimes you need to describe a simple action that's used only once and won't be useful anywhere else. Creating a separate method for it is like hammering a nail with a plane model toolkit. It's much easier to grab something handy and solve the task "on the spot".

Anonymous method is a temporary piece of code that doesn't need a name because it's used right where it's created. It:

  • Is declared inside another method.
  • Has no name.
  • Is usually used once — for example, passed to a delegate or subscribed to an event.

Nowadays lambda expressions (the => operator) are used more often, but understanding anonymous methods helps to get how delegates and the event model in C# work.

When are anonymous methods convenient?

  • You need to quickly pass a piece of logic as a parameter, e.g., for sorting, filtering, events, etc.
  • There's no point in cluttering the class with separate methods for one-off logic.
  • When you want the code to be compact and readable: all the "small business logic" in one place.

A bit of history

Anonymous methods first appeared in C# version 2.0. Before that using delegates was clumsy: you had to declare a separate named method even if its logic was used in one place. With anonymous methods things got simpler, and with lambdas this idea reached a new level of conciseness.

2. Classic: delegates and a usual "named" method

Before meeting anonymous methods, let's recall the standard way to pass behavior via delegates. Suppose we have a "Book database" app where we want to filter books by different conditions.

// Define the delegate
public delegate bool BookFilter(Book book);

// Book class
public class Book
{
    public string Title { get; set; }
    public int Year { get; set; }
}

Previously we wrote like this:

// Separate filter function
public static bool IsClassic(Book b)
{
    return b.Year < 1970;
}

// Somewhere in the application code
BookFilter filter = IsClassic;

Creating a separate method every time isn't always convenient. What if there are dozens of filters?

3. Anonymous method: minimalism, friendly with delegates

An anonymous method allows you to define the filter code right where you need it:

BookFilter filter = delegate(Book b)
{
    return b.Year < 1970;
};

That's it! No extra methods, everything in place. delegate acts as a declaration of an unnamed function.

General syntax

delegate([arguments])
{
    // method body
};

Example embedded in a program:

public class Book
{
    public string Title { get; set; }
    public int Year { get; set; }
}

public delegate bool BookFilter(Book book);

class Program
{
    static void Main()
    {
        Book[] books = {
            new Book { Title = "Master and Margarita", Year = 1967 },
            new Book { Title = "Clean Code", Year = 2008 }
        };

        // Anonymous filter for classics
        BookFilter filter = delegate(Book b)
        {
            return b.Year < 1970;
        };

        foreach (Book book in books)
        {
            if (filter(book)) // invoke the anonymous function!
                Console.WriteLine($"{book.Title} — classic!");
        }
    }
}

Output:

Master and Margarita — classic!

4. Anonymous method with different delegates

Anonymous methods work fine with all delegates. For example, the standard Action and Func<T, TResult>, which we'll cover in detail later.

Action<string> sayHello = delegate(string name)
{
    Console.WriteLine($"Hello, {name}!");
};

sayHello("World"); // Hello, World!

Short illustration: how a "one-off" anonymous method works

The easiest way to imagine an anonymous method is like a temporary worker: shows up for a short job, does it — and disappears. We bind the worker and the job via a delegate.

Func<int, int, int> sum = delegate (int a, int b) {
    return a + b;
};
Console.WriteLine(sum(5, 7)); // 12

Use cases: sorting, searching, collection processing

Suppose we have a list of books that we want to sort by publication year. Declaring a separate method for a one-off comparison is excessive.

var books = new List<Book>
{
    new Book { Title = "Master and Margarita", Year = 1967 },
    new Book { Title = "Clean Code", Year = 2008 }
};

books.Sort(delegate(Book a, Book b)
{
    return a.Year.CompareTo(b.Year);
});

foreach (var book in books)
    Console.WriteLine($"{book.Title} ({book.Year})");

5. Useful nuances

Is an anonymous method the same as a lambda expression?

In modern C# lambda expressions (=>) are used more often, and usually there's little difference, but there are some fundamental differences:

  • Lambdas are shorter and more expressive.
  • Lambdas have unambiguous variable capture rules (we'll learn this a bit later).
  • Anonymous methods appeared earlier and are sometimes found in legacy codebases.

Here's how our example would look with a lambda:

BookFilter filter = b => b.Year < 1970;

Still, knowing both old and new syntax is useful for interviews, reading other people's code and for a deep understanding of delegates.

Anonymous methods with and without parameters

If the delegate takes nothing, you can write it in one line:

Action printHello = delegate { Console.WriteLine("Hello!"); };
printHello(); // Hello!

If it takes parameters — you can still write it in one line:

Action<int> printSquare = delegate (int x) { Console.WriteLine(x * x); };
printSquare(6); // 36

Anonymous method and Lambda expression

Anonymous method Lambda expression
Syntax
delegate (...) {}
(args) => {}
Variable capture Yes Yes
Popularity Rarely used Standard
Return value Can/required Can/required
Multiline Possible Possible

6. Anonymous methods — small details and usage nuances

Capturing local variables
Anonymous methods can use variables from the surrounding method — this mechanism is called a "closure". For example:

int minYear = 1970;

BookFilter filter = delegate(Book book)
{
    return book.Year < minYear;
};

Console.WriteLine(filter(new Book { Title = "Test", Year = 1960 })); // True

If you later change minYear, the filter will use the new value!

You can omit parameters
If parameters aren't needed:

Action sayHi = delegate { Console.WriteLine("Hi!"); };

Passing null
If a delegate hasn't been assigned a method (for example, an anonymous one), its value is null, and attempting to invoke it will throw a NullReferenceException. Be careful.

Multiline
An anonymous method can contain a full block of code, conditions, loops and even other calls:

Action manyThings = delegate
{
    Console.WriteLine("We started!");
    for (int i = 0; i < 3; i++)
        Console.WriteLine(i);
    Console.WriteLine("We finished!");
};
manyThings();

7. Common mistakes and quirks

Sometimes developers confuse variable scope: capturing loop variables or nested-method variables can lead to surprising results.

List<Action> actions = new List<Action>();
for (int i = 0; i < 3; i++)
{
    actions.Add(delegate { Console.WriteLine(i); });
}
foreach (var action in actions) action(); // 3 3 3 — surprise!

The thing is an anonymous method "sees" the variable i — when the loop finished, i became 3. All methods print the same value. For correct behavior it's better to capture the variable like this:

for (int i = 0; i < 3; i++)
{
    int current = i;
    actions.Add(delegate { Console.WriteLine(current); });
}
2
Task
C# SELF, level 49, lesson 0
Locked
First practice with anonymous methods
First practice with anonymous methods
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION