Default Lambda Parameters in C# 12

Introduction

C# 12 adds another gem to this collection: default lambda parameters. This game-changing feature allows you to assign default values to parameters within lambda expressions, ushering in a paradigm shift toward conciseness and readability. Let's delve into this exciting addition, exploring its functionalities, advantages, and practical applications through detailed examples.

Default Values

Prior to C# 12, achieving flexible lambda functions often involved lengthy method signatures or cumbersome logic to handle optional parameters. Default lambda parameters break free from these shackles, enabling you.

  • Reduce Code Duplication: Eliminate the need to repeatedly specify common parameter values, leading to cleaner and more maintainable code.
  • Enhance Readability: Focus on the core logic of your lambda functions by minimizing visual clutter and redundant code blocks.
  • Embrace Flexibility: Design versatile functions that adapt to various scenarios without sacrificing conciseness, simplifying implementation and usage.

Navigating the Syntax

Defining default lambda parameters is remarkably straightforward. Simply specify the parameter name followed by an equal sign and the desired default value, enclosed within parentheses.

(parameter1 = defaultValue1, parameter2 = defaultValue2) => expression

Now, let's witness the magic of default lambda parameters in action through illustrative examples across diverse scenarios.

1. String Manipulation

Imagine a function that transforms strings by adding prefixes and suffixes.

string TransformString(string input, string prefix = "Hello, ", string suffix = "!") => prefix + input + suffix;

Console.WriteLine(TransformString("World")); // Output: Hello, World!
Console.WriteLine(TransformString("C# 12", "Welcome to ")); // Output: Welcome to C# 12!

Here, default values for prefixes and suffixes are provided, allowing you to call the function with or without specifying them. Omitting the parameters defaults to the pre-defined values, promoting concise and clear calls.

2. Conditional Operations

Consider a function that performs an action based on a Boolean condition.

Action PerformAction(bool condition = true) => condition ? () => Console.WriteLine("Action executed!") : null;

PerformAction();   // Output: Action executed!
PerformAction(false); // No output

The default true for condition ensures the action is executed by default unless explicitly specified as false. This eliminates the need for lengthy if-else statements, resulting in a more succinct and readable approach.

3. Filtering Collections

Filtering even numbers from a collection becomes a breeze with default parameters.

IEnumerable<int> FilterEvenNumbers(IEnumerable<int> numbers, int threshold = 10) => numbers.Where(x => x % 2 == 0 && x >= threshold);

int[] numbers = { 5, 8, 12, 16, 20 };
var filteredNumbers = FilterEvenNumbers(numbers); // filteredNumbers: { 12, 16, 20 }

The default threshold of 10 allows filtering even numbers above a certain limit. Adjusting this value provides flexibility without altering the function's core logic.

4. Handling Asynchronous Operations

Default parameters shine even in asynchronous scenarios.

async Task<int> GetDataAsync(int requestId, CancellationToken token = default) => await Task.FromResult(42);

// ...

Providing a default CancellationToken streamlines asynchronous operations by handling cancellation without additional parameters.

Remember

  • Default values must be compile-time constants.
  • Expressions, including method calls, can be used for default values.
  • Regular lambda parameters can be combined with defaults.
  • Default lambda parameters extend to anonymous methods and local functions.

Here's a program snippet that demonstrates how to leverage default lambda parameters, filtering, conditional logic, and asynchronous operations.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace DefaultLambdaParametersDemo
{
    class Program
    {
        static async Task Main(string[] args)
        {
            // Sample data
            List<int> numbers = new List<int>() { 5, 8, 12, 16, 20, 22 };

            // Filter even numbers above a threshold and perform conditional actions
            IEnumerable<int> filteredNumbers = FilterEvenNumbers(numbers, threshold: 15);

            foreach (int number in filteredNumbers)
            {
                Action action = PerformAction(number % 4 == 0); // Use default condition for divisibility by 4
                action?.Invoke();  // Execute action if it's not null
            }

            // Simulate an asynchronous operation with default cancellation token
            int result = await GetDataAsync(requestId: 1);
            Console.WriteLine($"Asynchronous result: {result}");
        }

        // Function with default lambda parameters
        static IEnumerable<int> FilterEvenNumbers(IEnumerable<int> numbers, int threshold = 10)
        {
            return numbers.Where(x => x % 2 == 0 && x >= threshold);
        }

        // Function with conditional logic and default lambda parameter
        static Action PerformAction(bool condition = true)
        {
            return condition ? () => Console.WriteLine("Action executed for number!") : null;
        }

        // Asynchronous function with default cancellation token
        static async Task<int> GetDataAsync(int requestId, CancellationToken token = default)
        {
            await Task.Delay(2000, token);  // Simulate a delay with cancellation support
            return 42; // Sample result
        }
    }
}

Key points in this example

  • Default lambda parameters: FilterEvenNumbers and PerformAction use them for threshold and condition to provide flexibility and conciseness.
  • Filtering: FilterEvenNumbers demonstrates filtering even numbers based on a threshold using LINQ's Where method.
  • Conditional logic: PerformAction conditionally creates an action based on a default condition, avoiding unnecessary if-else statements.
  • Asynchronous operations: GetDataAsync simulates an asynchronous operation with a default cancellation token for proper resource management.

This snippet showcases how these features work together to create code.

  • Concise: Default parameters reduce verbosity and promote cleaner code.
  • Flexible: Functions can adapt to different scenarios without complex logic.
  • Readable: Clearer expression of intent and less clutter.
  • Efficient: Asynchronous operations with cancellation support for responsiveness.

Conclusion

Default lambda parameters mark a significant leap forward in C# development. By embracing this powerful feature, you can unleash your creativity, crafting concise, clear, and versatile code that sings with elegance and efficiency. So, dive into the exciting world of default lambda parameters and experience the transformation in your C# coding journey!

This article presents just a glimpse into the vast potential of default lambda parameters. As you delve deeper into this feature, explore its application in areas like event handling, data validation, and functional programming. Embrace the endless possibilities and watch your C# code reach new heights of expressiveness and maintainability.


Similar Articles