C# > Functional Programming > Lambdas and Expressions > Lambda Expressions Syntax

Lambda Expressions: Basic Syntax and Usage

This snippet demonstrates the fundamental syntax of lambda expressions in C# and provides a simple example of how to use them with LINQ's Where method to filter a list of integers.

Basic Lambda Syntax

This code illustrates the basic syntax of lambda expressions:

  1. (input parameters) => expression or statement block
  2. The => operator separates the input parameters from the lambda body.
  3. If there is only one input parameter, the parentheses can be omitted.
  4. If the lambda body is a single expression, it is implicitly returned.
  5. If the lambda body is a statement block (enclosed in {}), you need to use a return statement to return a value.
  6. Func is a built-in delegate type in C# that represents a function that takes zero or more input parameters and returns a value. Func represents a function that takes an integer and returns an integer. Func represents a function that takes two integers and returns an integer. Func represents a function that takes no arguments and returns an integer.

/*
Lambda Expression Syntax:
(input parameters) => expression or statement block
*/

// Example 1: Lambda expression with a single parameter
// that returns the square of the number.
Func<int, int> square = x => x * x;

// Example 2: Lambda expression with multiple parameters
// that returns the sum of two numbers.
Func<int, int, int> add = (x, y) => x + y;

// Example 3: Lambda expression with no parameters
// that returns a constant value.
Func<int> getFive = () => 5;

// Example 4: Lambda expression with a statement block
// that prints a message and returns a boolean.
Func<string, bool> isLongString = str =>
{
    Console.WriteLine("Checking string length...");
    return str.Length > 10;
};


Console.WriteLine($"Square of 5: {square(5)}");
Console.WriteLine($"Sum of 3 and 7: {add(3, 7)}");
Console.WriteLine($"Value from getFive: {getFive()}");
Console.WriteLine($"Is 'HelloWorld!' a long string? {isLongString("HelloWorld!")}");

Using Lambda Expressions with LINQ

This code demonstrates how to use a lambda expression with LINQ's Where method to filter a list of integers. The Where method takes a delegate (in this case, a lambda expression) as an argument. The lambda expression x => x % 2 == 0 checks if a number is even. LINQ provides a powerful way to query and manipulate data using lambda expressions.

using System;
using System.Collections.Generic;
using System.Linq;

public class LambdaExample
{
    public static void Main(string[] args)
    {
        List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        // Using a lambda expression to filter even numbers
        IEnumerable<int> evenNumbers = numbers.Where(x => x % 2 == 0);

        Console.WriteLine("Even numbers:");
        foreach (int num in evenNumbers)
        {
            Console.WriteLine(num);
        }
    }
}

Concepts Behind the Snippet

The core concept is that lambda expressions provide a concise way to define anonymous functions (functions without a name) inline. They are particularly useful when passing functions as arguments to other methods, as demonstrated with LINQ. Understanding delegates (function pointers) is also important for grasping how lambda expressions work. A delegate is a type-safe way to represent a function.

Real-Life Use Case

Lambda expressions are commonly used in event handling (e.g., attaching a method to a button click event), asynchronous programming (e.g., defining the callback function for a task), and data transformations (e.g., mapping a list of objects to a list of strings). Imagine filtering a list of products based on price or category, which can be easily achieved using lambda expressions with LINQ.

Best Practices

  • Keep lambda expressions short and focused. If a lambda expression becomes too complex, consider refactoring it into a separate named method.
  • Use meaningful parameter names to improve readability.
  • Avoid capturing variables that are modified outside the lambda expression (closure pitfalls).
  • Consider the performance implications of using lambda expressions in performance-critical sections of code. In some cases, using a named method might be more efficient.

Interview Tip

Be prepared to explain the syntax of lambda expressions, how they relate to delegates, and common use cases. You should also be able to write simple lambda expressions on the spot. A common question is to write a lambda expression that squares a number or filters a list of strings based on length.

When to Use Them

Use lambda expressions when you need to pass a short, simple function as an argument to another method, especially with LINQ, event handlers, and asynchronous operations. They are ideal for situations where you don't need to reuse the function in multiple places.

Memory Footprint

Lambda expressions themselves don't inherently create a large memory footprint. However, the objects they capture (variables from the surrounding scope, known as closures) can contribute to memory usage if not managed carefully. Be mindful of the lifetime of captured variables, especially in long-running processes.

Alternatives

Alternatives to lambda expressions include named methods, anonymous delegates (using the delegate keyword), and, in some cases, simple loop constructs. Named methods are generally preferred for complex functions or when code reuse is required. Anonymous delegates offer similar functionality to lambda expressions but with a more verbose syntax.

Pros

  • Concise syntax: Lambda expressions provide a compact way to define functions.
  • Improved readability: They can make code more readable, especially when used with LINQ.
  • Flexibility: They can be used in various contexts, such as LINQ, event handling, and asynchronous programming.

Cons

  • Potential for reduced readability: Complex lambda expressions can be difficult to understand.
  • Debugging challenges: Debugging lambda expressions can be more challenging than debugging named methods.
  • Closure pitfalls: Capturing variables from the surrounding scope can lead to unexpected behavior if not handled carefully.

FAQ

  • What is a delegate in C#?

    A delegate is a type that represents a reference to a method. It's similar to a function pointer in C++ but is type-safe. Delegates allow you to pass methods as arguments to other methods.
  • Can I use multiple statements in a lambda expression?

    Yes, you can use multiple statements in a lambda expression by enclosing them in curly braces {}. This creates a statement block. Remember to use the return statement if you want to return a value from the lambda expression.
  • What is a closure in the context of lambda expressions?

    A closure is the concept where a lambda expression can access variables from its surrounding scope (the scope where it was defined). This means the lambda expression 'closes over' these variables. Be careful when modifying these captured variables outside the lambda, as it can lead to unexpected results.