13. Anonymous Method, Lambda Expression

Anonymous Methods

Anonymous methods are functions without a name, defined inline where they are needed. They are useful when you want to create a quick method body to be used once or in a localized scope, typically assigned to a delegate.

Example of attaching an anonymous method to a delegate:

del += delegate
{
    Console.WriteLine("Goodbye!");
};

However, because this method has no name, you cannot easily remove (-=) exactly the same anonymous handler later.

Parameterless Anonymous Delegate

public delegate void AnonimDelegate();

AnonimDelegate del = delegate
{
    Console.WriteLine("Hi Guys, What's up");
};
del(); // Invokes the method

Anonymous Delegate with Parameters

public delegate void AnonimDelegateInt(int no);

AnonimDelegateInt delInt = delegate (int no)
{
    Console.WriteLine(no);
};
delInt(42);

While anonymous methods are convenient, if you need to unsubscribe from an event or re-use the method in multiple places, it is usually better to use named methods.

Lambda Expressions

A lambda expression (arrow function) is another way of writing an anonymous method, with an even more concise syntax. In C#, the syntax is (parameters) => expression_or_block.

Examples

  1. Parameterless lambda:
    Action greet = () => Console.WriteLine("Hello from Lambda!");
    greet();
  1. Lambda with parameters:
    Action<int> printNumber = n => Console.WriteLine($"Number: {n}");
    printNumber(10);
  1. Lambda with multiple statements:
    Func<int, int, int> add = (x, y) =>
    {
        int sum = x + y;
        return sum;
    };
    int result = add(3, 4); // result = 7

Extension Methods and LINQ

Extension methods let you add new methods to existing types without modifying them. LINQ (Language Integrated Query) relies heavily on extension methods, such as Where, Select, OrderBy, etc.

Using LINQ Extension Methods

  1. First() returns the first element of a sequence, but throws an exception if none is found.
  1. FirstOrDefault() returns the first element or a default value (null or default(T)) if none is found.
  1. Single() expects exactly one matching element. If zero or more than one match is found, it throws an exception.
  1. SingleOrDefault() returns the element if exactly one match is found, otherwise returns null (or default(T)).
  1. Take(n) gets the first n elements.
  1. Skip(n) ignores the first n elements and returns the rest.
  1. TakeWhile(condition) takes elements while the condition is true, then stops.
  1. SkipWhile(condition) skips elements while the condition is true, then starts returning elements once it becomes false.
  1. OrderBy(...) sorts the sequence in ascending order.
  1. OrderByDescending(...) sorts in descending order.
  1. Where(...) filters elements based on a predicate.
  1. FindIndex(...) for arrays or lists, finds the index of the first element matching a condition, or returns -1 if not found.
  1. IndexOf(...) finds the index of a specific object if it exists, or returns -1.
  1. Remove(...), RemoveAt(...), RemoveAll(...) remove items from a list.

Example filtering a list with Where:

List<int> numbers = new List<int> {1, 2, 3, 4, 5, 6};
var evenNumbers = numbers.Where(n => n % 2 == 0);
foreach (var number in evenNumbers)
{
    Console.WriteLine(number);
}

This returns only the even numbers from the list.

Reference

The content in this document is based on the original notes provided in Azerbaijani. For further details, you can refer to the original document using the following link:

Original Note - Azerbaijani Version