Anonymous Functions that contain expressions or a succession of operators are known as Lambda Expressions. The lambda operator =>, which may be read as “goes to” or “becomes,” is used in all lambda expressions. The Input Parameters are specified on the left side of the Lambda Operator, while the right side contains an expression or a code block that works with the entry arguments. Lambda expressions are commonly used as predicates or instead of delegates (a type that references a method).

In this article and code examples, you will see how to implement C# Lambda function in different Use Cases.

What is C#?

C# Lambda: C# logo

C# (pronounced “C sharp”) is a general-purpose, contemporary, and object-oriented programming language. It was created by Microsoft as part of the .Net program, coordinated by Anders Hejlsberg and his team, and was authorized by the European Computer Manufacturers Association (ECMA) and the International Standards Organization (ISO). The current version of C# is version 7.2, and it is one of the languages for Common Language Infrastructure. C# is syntactically similar to Java and is simple for users who are familiar with C, C++, or Java.

Key Features of C# Programming

  • Simple to Use: In the sense that it provides a structured approach (to break the problem into sections), a comprehensive set of library functions, data types, and so on, C# is a straightforward language.
  • Modern Language: C# programming is incredibly powerful and straightforward for constructing Scalable, Interoperable, and Robust Systems, and it is based on the current trend.
  • OOPs: The C# programming language is an object-oriented programming language. OOPs simplifies development and maintenance, whereas Procedure-oriented programming languages are difficult to handle as projects expand in size.
  • Memory Access: Safe code written in C# can only visit memory locations where it has been granted permission to run. As a result, the program’s security is improved.
  • Interoperability: C# programs can perform practically everything a native C++ application can do thanks to the interoperability process.
  • Scaleable and Updateable: C# is a programming language that is automatically scalable and updateable. We erase old files and replace them with new ones when we update our application.
  • Component Oriented: The C# programming language is a component-oriented programming language. It is the most widely used software development process for creating more resilient and scalable applications.
  • Structured Programming language: In the sense that we may separate the program into portions using functions, C# is a structured programming language. As a result, it is simple to comprehend and alter.
  • Library: C# has a variety of built-in utilities that make development go quickly.
  • Fast Speed: The C# language has a quick compilation and execution time.

What are Anonymous/Lambda Functions in C#?

An Anonymous Function, which was introduced in C# 2.0, is a function that doesn’t have a name. When a user wishes to build an i=Inline function and also send parameters to the anonymous function like other functions, this is beneficial. The delegate keyword is used to construct an anonymous function, which the user can then assign to a delegate type variable.

What’s the importance of C# Lambda Functions?

In C#, Lambda Expressions are similar to Anonymous Functions, with the exception that you don’t have to define the type of the value you’re passing in, making them more versatile.

The Lambda Operator, which is utilised in all lambda expressions, is ‘=>‘. The input is on the left side of the C# Lambda Expression, while the Expression is on the right.

Syntax of C# Lambda Functions

On the left side of the Operator, you specify Input Parameters (if any), and on the right side, you specify an expression or a statement block.

A delegate type can be created from any C# Lambda Expression. The types of a Lambda Expression’s Parameters and Return Value determine the delegate type to which it can be transformed. A Lambda Expression can be changed to one of the Action delegate types if it doesn’t return a value; otherwise, it can be converted to one of the Func delegate types.

For example, a C# Lambda Expression with two parameters and no return value can be transformed to an Action<T1,T2> delegate. A Func<T,TResult> delegate can be converted from a lambda expression C# with one parameter and returns a value. The C# lambda phrase x => x * x, which provides a parameter named x and returns the value of x squared, is assigned to a delegate type variable in the following example:

Func<int, int> square = x => x * x;
Console.WriteLine(square(5));
// Output:
// 25

What are the Types for Lambda Functions in C#? 

Statement Lambdas

The only difference between a Statement Lambda and an Expression Lambda is that the statements are contained in braces:

(input-parameters) => { <sequence-of-statements> }

The body of a Statement Lambda can include any number of statements; however, in practice, no more than two or three are usually used.

Action<string> greet = name =>
{
    string greeting = $"Hello {name}!";
    Console.WriteLine(greeting);
};
greet("World");
// Output:
// Hello World!

You can’t make expression trees with Statement Lambdas.

Expression Lambdas

An Expression Lambda is a lambda expression with an expression on the right side of the => operator. The outcome of an expression is returned by an Expression Lambda, which has the following fundamental form: 

(input-parameters) => expression

A method call can be the body of an Expression Lambda. You shouldn’t use method calls in lambda expressions if you’re generating expression trees that are evaluated outside of the .NET Common Language Runtime (CLR), such as in SQL Server. Outside of the.NET Common Language Runtime (CLR), the methods will be meaningless.

What are the Async Lambdas in C#? 

Using the async and await keywords, you can quickly write C# lambda expressions and statements that include asynchronous processing. For example, in the Windows Forms example below, an event handler calls and awaits ExampleMethodAsync, an async method.

Using an async C# lambda, you may add the same event handler. Add an async modifier before the C# lambda parameter list to add this handler, as shown in the example below:

See Asynchronous Programming with async and await for more information on how to construct and use async methods.

How to use C# Lambda Input Parameters?

A C# Lambda Expression’s Input Parameters are enclosed in Parentheses. Use empty Parenthesis to specify zero Input Parameters:

Action line = () => Console.WriteLine();

Parentheses are optional when a Lambda Expression has only one Input Parameter:

Func<double, double> cube = x => x * x * x;

Commas are used to separate two or more Input Parameters:

Func<int, int, bool> testForEquality = (x, y) => x == y;

In some cases, the compiler is unable to determine the types of Input Arguments. As seen in the following example, you can define the kinds explicitly:

Func<int, string, bool> isTooLong = (int x, string s) => s.Length > x;

A CS0748 compiler error occurs if Input Parameter types are not all explicit or all implicit. When using a Lambda Expression to provide an event handler, discarding Parameters may be handy. You can use discards to define two or more input arguments of a Lambda Expression that aren’t used in the expression starting with C# 9.0:

Func<int, int, int> constant = (_, _) => 42;

When using a Lambda Expression to provide an Event Handler, discard parameters may be handy.

How to use C# Lambda Expressions with Tuples?

Tuples are supported by the C# language starting with version 7.0. A Tuple can be passed as an argument to a Lambda Expression, and the Lambda Expression can return a Tuple as well. The C# compiler utilizes type inference to determine the types of Tuple Components in some circumstances.

In parenthesis, you define a Tuple by enclosing a comma-delimited list of its components. The following example utilizes a three-component tuple to send a sequence of numbers to a Lambda Expression, which doubles each value and returns a three-component tuple containing the multiplication result.

Func<(int, int, int), (int, int, int)> doubleThem = ns => (2 * ns.Item1, 2 * ns.Item2, 2 * ns.Item3);
var numbers = (2, 3, 4);
var doubledNumbers = doubleThem(numbers);
Console.WriteLine($"The set {numbers} doubled: {doubledNumbers}");
// Output:
// The set (2, 3, 4) doubled: (4, 6, 8)

The fields of a tuple are usually referred to as Item1, Item2, and so on. However, as shown in the following example, you can define a Tuple with named components.

Func<(int n1, int n2, int n3), (int, int, int)> doubleThem = ns => (2 * ns.n1, 2 * ns.n2, 2 * ns.n3);
var numbers = (2, 3, 4);
var doubledNumbers = doubleThem(numbers);
Console.WriteLine($"The set {numbers} doubled: {doubledNumbers}");

See Tuple types for further information on C# Tuples.

How to use Query Parameters in C# Lambda Expressions?

Input Parameters of the FuncTResult> family of generic delegates are used in LINQ to Objects and other implementations. The number and type of input arguments, as well as the delegate’s return type, are defined by type parameters in these delegates. User-defined expressions that are applied to each element in a set of source data are encapsulated by func delegates. Take the delegate type Func<T,TResult> for example:

public delegate TResult Func<in T, out TResult>(T arg)

The delegate can be created as a Func<int, bool> instance, with int as the input parameter and bool as the return value. The last type parameter always specifies the return value. Func<int, string, bool>, for example, is a delegate with two int and string Input Parameters and a bool return type. When the following Func delegate is called, it returns a Boolean value indicating whether the Input Parameter is greater than five:

Func<int, bool> equalsFive = x => x == 5;
bool result = equalsFive(4);
Console.WriteLine(result);   // False

When the parameter type is an Expression<TDelegate>, as in the Standard Query Operators defined in the Queryable type, you can additionally supply a Lambda Expression. The Lambda is compiled into an expression tree when you use the Expression<TDelegate> Parameter.

The following example uses the Count Standard Query Operator:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddNumbers = numbers.Count(n => n % 2 == 1);
Console.WriteLine($"There are {oddNumbers} odd numbers in {string.Join(" ", numbers)}");

The type of Input Parameter can be inferred by the compiler, or you can define it explicitly. This Lambda Expression counts the number of integers (n) that have a remainder of 1 when divided by 2.

Since 9 is the first number in the sequence that doesn’t match the criterion, the next example generates a sequence that contains all entries in the numbers array that come before it.

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstNumbersLessThanSix = numbers.TakeWhile(n => n < 6);
Console.WriteLine(string.Join(" ", firstNumbersLessThanSix));
// Output:
// 5 4 1 3

By encapsulating several Input Parameters in parenthesis, the following example defines multiple Input Parameters. Until it discovers a number whose value is less than its ordinal position in the array, the procedure returns all the entries in the numbers array:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
Console.WriteLine(string.Join(" ", firstSmallNumbers));
// Output:
// 5 4

Lambda Expressions aren’t directly used in Query Expressions, although they can be used in method calls within Query Expressions as the following example shows:

var numberSets = new List<int[]>
{
    new[] { 1, 2, 3, 4, 5 },
    new[] { 0, 0, 0 },
    new[] { 9, 8 },
    new[] { 1, 0, 1, 0, 1, 0, 1, 0 }
};

var setsWithManyPositives = 
    from numberSet in numberSets
    where numberSet.Count(n => n > 0) > 3
    select numberSet;

foreach (var numberSet in setsWithManyPositives)
{
    Console.WriteLine(string.Join(" ", numberSet));
}
// Output:
// 1 2 3 4 5
// 1 0 1 0 1 0 1 0

Examples of using Lambda Expressions in C#

Sorting Values using Lambdas

An example of sorting with a Lambda Expression is as follows:

var sortedDogs = dogs.OrderByDescending(x => x.Age);  
foreach (var dog in sortedDogs)   
{  
   Console.WriteLine(string.Format("Dog {0} is {1} years old.", dog.Name, dog.Age));  
}  

Output:

Dog Rex is 4 years old.
Dog Stacy is 3 years old.
Dog Sean is 0 years old.

Evaluating Expressions using Lambda Expressions

using System;  
using System.Collections.Generic;  
using System.Linq;  
class Dog  
{  
   public string Name { get; set; }  
   public int Age { get; set; }   
}    
class demo{  
   static void Main()  
   {  
      List<Dog> dogs = new List<Dog>() {   
         new Dog { Name = "Rex", Age = 4 },  
         new Dog { Name = "Sean", Age = 0 },  
         new Dog { Name = "Stacy", Age = 3 }  
      };  
      var newDogsList = dogs.Select(x => new { Age = x.Age, FirstLetter = x.Name[0] });  
      foreach (var item in newDogsList)  
      {   
         Console.WriteLine(item);  
      }   
      Console.Read();  
   }  
}  

Output: 

{ Age = 4, FirstLetter = R }
{ Age = 0, FirstLetter = S }
{ Age = 3, FirstLetter = S }

The anonymous type items in the newly constructed collection newDogsList have the values Age and FirstLetter as Arguments.

How to use Attributes with C# Lambda Expressions?

A Lambda Expression and its parameters can now have properties starting with C# 10. The example below demonstrates how to add characteristics to a Lambda Expression:

Func<string, int> parse = [Example(1)] (s) => int.Parse(s);
var choose = [Example(2)][Example(3)] object (bool b) => b ? 1 : "two";

As shown in the following example, you may additionally add properties to the Input Parameters or Return Value:

var sum = ([Example(1)] int a, [Example(2), Example(3)] int b) => a + b;
var inc = [return: Example(1)] (int s) => s++;

When adding characteristics to a Lambda Expression or its parameters, you must parenthesize the Input Parameters, as shown in the preceding examples.

Learn More About:

Conclusion

In this article, you saw how to implement the C# Lambda function in different Use Cases. You got a deep understanding of the different types of scenarios you may encounter while using the Lambda function. In case you want to export data from a source of your choice into your desired Database/destination then Hevo Data is the right choice for you! 

Share your experience of learning about the C# Lambda function! Let us know in the comments section below!

Harsh Varshney
Research Analyst, Hevo Data

Harsh is a data enthusiast with over 2.5 years of experience in research analysis and software development. He is passionate about translating complex technical concepts into clear and engaging content. His expertise in data integration and infrastructure shines through his 100+ published articles, helping data practitioners solve challenges related to data engineering.