C# Programming Guide
Lambda Expressions (C# Programming Guide)

Updated: July 2009

A lambda expression is an anonymous function that can contain expressions and statements, and can be used to create delegates or expression tree types.

All lambda expressions use the lambda operator =>, which is read as "goes to". The left side of the lambda operator specifies the input parameters (if any) and the right side holds the expression or statement block. The lambda expression x => x * x is read "x goes to x times x." This expression can be assigned to a delegate type as follows:

C#
delegate int del(int i);
static void Main(string[] args)
{
    del myDelegate = x => x * x;
    int j = myDelegate(5); //j = 25
}

To create an expression tree type:

C#
using System.Linq.Expressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<del> myET = x => x * x;
        }
    }
}

The => operator has the same precedence as assignment (=) and is right-associative.

Lambdas are used in method-based LINQ queries as arguments to standard query operator methods such as Where.

When you use method-based syntax to call the Where method in the Enumerable class (as you do in LINQ to Objects and LINQ to XML) the parameter is a delegate type System..::.Func<(Of <(T, TResult>)>). A lambda expression is the most convenient way to create that delegate. When you call the same method in, for example, the System.Linq..::.Queryable class (as you do in LINQ to SQL) then the parameter type is an System.Linq.Expressions..::.Expression<Func> where Func is any Func delegates with up to four input parameters. Again, a lambda expression is just a very concise way to construct that expression tree. The lambdas allow the Where calls to look similar although in fact the type of object created from the lambda is different.

In the previous example, notice that the delegate signature has one implicitly-typed input parameter of type int, and returns an int. The lambda expression can be converted to a delegate of that type because it also has one input parameter (x) and a return value that the compiler can implicitly convert to type int. (Type inference is discussed in more detail in the following sections.) When the delegate is invoked by using an input parameter of 5, it returns a result of 25.

Lambdas are not allowed on the left side of the is or as operator.

All restrictions that apply to anonymous methods also apply to lambda expressions. For more information, see Anonymous Methods (C# Programming Guide).

Expression Lambdas

A lambda expression with an expression on the right side is called an expression lambda. Expression lambdas are used extensively in the construction of Expression Trees. An expression lambda returns the result of the expression and takes the following basic form:

(input parameters) => expression

The parentheses are optional only if the lambda has one input parameter; otherwise they are required. Two or more input parameters are separated by commas enclosed in parentheses:

(x, y) => x == y

Sometimes it is difficult or impossible for the compiler to infer the input types. When this occurs, you can specify the types explicitly as shown in the following example:

(int x, string s) => s.Length > x

Specify zero input parameters with empty parentheses:

() => SomeMethod()

Note in the previous example that the body of an expression lambda can consist of a method call. However, if you are creating expression trees that will be consumed in another domain, such as SQL Server, you should not use method calls in lambda expressions. The methods will have no meaning outside the context of the .NET common language runtime.

Statement Lambdas

A statement lambda resembles an expression lambda except that the statement(s) is enclosed in braces:

(input parameters) => {statement;}

The body of a statement lambda can consist of any number of statements; however, in practice there are typically no more than two or three.

delegate void TestDelegate(string s);
…
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");

Statement lambdas, like anonymous methods, cannot be used to create expression trees.

Lambdas with the Standard Query Operators

Many Standard query operators have an input parameter whose type is one of the Func<(Of <(T, TResult>)>) family of generic delegates. The Func<(Of <(T, TResult>)>) delegates use type parameters to define the number and type of input parameters, and the return type of the delegate. Func delegates are very useful for encapsulating user-defined expressions that are applied to each element in a set of source data. For example, consider the following delegate type:

public delegate TResult Func<TArg0, TResult>(TArg0 arg0)

The delegate can be instantiated as Func<int,bool> myFunc where int is an input parameter and bool is the return value. The return value is always specified in the last type parameter. Func<int, string, bool> defines a delegate with two input parameters, int and string, and a return type of bool. The following Func delegate, when it is invoked, will return true or false to indicate whether the input parameter is equal to 5:

    Func<int, bool> myFunc = x => x == 5;
    bool result = myFunc(4); // returns false of course

You can also supply a lambda expression when the argument type is an Expression<Func>, for example in the standard query operators that are defined in System.Linq.Queryable. When you specify an Expression<Func> argument, the lambda will be compiled to an expression tree.

A standard query operator, the Count method, is shown here:

    int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
    int oddNumbers = numbers.Count(n => n % 2 == 1);

The compiler can infer the type of the input parameter, or you can also specify it explicitly. This particular lambda expression counts those integers (n) which when divided by two have a remainder of 1.

The following method will produce a sequence that contains all the elements in the numbers array that are to the left of the “9” because that is the first number in the sequence that does not meet the condition:

    var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);

This example shows how to specify multiple input parameters by enclosing them in parentheses. The method returns all the elements in the numbers array until a number is encountered whose value is less than its position. Do not confuse the lambda operator (=>) with the greater than or equal operator (>=).

    var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);
Type Inference in Lambdas

When writing lambdas, you often do not have to specify a type for the input parameters because the compiler can infer the type based on the lambda body, the underlying delegate type, and other factors as described in the C# 3.0 Language Specification. For most of the standard query operators, the first input is the type of the elements in the source sequence. So if you are querying an IEnumerable<Customer>, then the input variable is inferred to be a Customer object, which means you have access to its methods and properties:

customers.Where(c => c.City == "London");

The general rules for lambdas are as follows:

  • The lambda must contain the same number of parameters as the delegate type.

  • Each input parameter in the lambda must be implicitly convertible to its corresponding delegate parameter.

  • The return value of the lambda (if any) must be implicitly convertible to the delegate's return type.

Note that lambda expressions in themselves do not have a type because the common type system has no intrinsic concept of "lambda expression." However, it is sometimes convenient to speak informally of the "type" of a lambda expression. In these cases the type refers to the delegate type or Expression type to which the lambda expression is converted.

Variable Scope in Lambda Expressions

Lambdas can refer to outer variables that are in scope in the enclosing method or type in which the lambda is defined. Variables that are captured in this manner are stored for use in the lambda expression even if variables would otherwise go out of scope and be garbage collected. An outer variable must be definitely assigned before it can be consumed in a lambda expression. The following example demonstrates these rules:

delegate bool D();
    delegate bool D2(int i);

    class Test
    {
        D del;
        D2 del2;
        public void TestMethod(int input)
        {
            int j = 0;
            // Initialize the delegates with lambda expressions.
            // Note access to 2 outer variables.
            // del will be invoked within this method.
            del = () => { j = 10;  return j > input; };

            // del2 will be invoked after TestMethod goes out of scope.
            del2 = (x) => {return x == j; };
            
            // Demonstrate value of j:
            // Output: j = 0 
            // The delegate has not been invoked yet.
            Console.WriteLine("j = {0}", j);

            // Invoke the delegate.
            bool boolResult = del();

            // Output: j = 10 b = True
            Console.WriteLine("j = {0}. b = {1}", j, boolResult);
        }

        static void Main()
        {
            Test test = new Test();
            test.TestMethod(5);

            // Prove that del2 still has a copy of
            // local variable j from TestMethod.
            bool result = test.del2(10);

            // Output: True
            Console.WriteLine(result);
            
            Console.ReadKey();
        }
    }

The following rules apply to variable scope in lambda expressions:

  • A variable that is captured will not be garbage-collected until the delegate that references it goes out of scope.

  • Variables introduced within a lambda expression are not visible in the outer method.

  • A lambda expression cannot directly capture a ref or out parameter from an enclosing method.

  • A return statement in a lambda expression does not cause the enclosing method to return.

  • A lambda expression cannot contain a goto statement, break statement, or continue statement whose target is outside the body or in the body of a contained anonymous function.

C# Language Specification

For more information, see the following section in the C# Language Specification:

  • 5.3.3.29 Anonymous functions

See Also

Concepts

Reference

Other Resources

Change History

Date

History

Reason

July 2009

Expanded the first two code segments.

Information enhancement.

January 2010

Fixed an error.

Customer feedback.

Tags :


Community Content

Mr.Novice
The New Lambda Expressions Feature in C# 3.0

C# 2.0 (released in November 2005) introduced a new feature, anonymous methods, that allows you to declare your method code inline instead of with a delegate function. Lambda expressions, a new feature in C# 3.0, have a more concise syntax to achieve the same goal. Take a closer look at anonymous methods before discussing lambda expressions.

Suppose you want to create a button that updates a ListBox on your form when you click it. In C# 1.0 and 1.1, you would do it as follows:

public MyForm()
{
listBox = new ListBox(...);
textBox = new TextBox(...);
addButton = new Button(...);
addButton.Click += new EventHandler(AddClick);
}
void AddClick(object sender, EventArgs e)
{
listBox.Items.Add(textBox.Text);
}

With C# 2.0, you could have it as under:

public MyForm()
{
listBox = new ListBox(...);
textBox = new TextBox(...);
addButton = new Button(...);
addButton.Click += delegate
{
listBox.Items.Add(textBox.Text);
};

As you can see, you don't have to explicitly declare a new method to link it with an event. You can use anonymous methods to achieve the same thing in C# 2.0. C# 3.0 introduces an even simpler syntax, lambda expressions, which you write as a parameter list followed by the "=>" token, followed by an expression or a statement block.

Parameters to Lambda Expressions

The parameters of a lambda expression can be explicitly or implicitly typed. In an explicitly typed parameter list, the type of each expression is explicitly specified. In an implicitly typed parameter list, the types are inferred from the context in which the lambda expression occurs:

(int x) => x + 1          // explicitly typed parameter
(y,z) => return y * z; // implicitly typed parameter

Lambda Expressions Demonstration

The following code snippet from the downloadable source code uses two techniques to print out strings in a list whose length is even. The first technique, implemented in the function AnonMethod, is through anonymous methods. The second technique, implemented in the function LambdaExample, is through a lambda expression:

// Program.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Query;
using System.Xml.XLinq;
using System.Data.DLinq;
namespace LambdaExample
{
public delegate bool KeyValueFilter<K, V>(K key, V value);
static class Program
{
static void Main(string[] args)
{
List<string> list = new List<string>();
list.Add("AA");
list.Add("ABC");
list.Add("DEFG");
list.Add("XYZ");
Console.WriteLine("Through Anonymous method");
AnonMethod(list);
Console.WriteLine("Through Lambda expression");
LambdaExample(list);
Dictionary<string, int> varClothes= new Dictionary<string,int>();
varClothes.Add("Jeans", 20);
varClothes.Add("Shirts", 15);
varClothes.Add("Pajamas", 9);
varClothes.Add("Shoes", 9);
var ClothesListShortage = varClothes.FilterBy((string name,
int count) => name == "Shoes" && count < 10);
// example of multiple parameters
if(ClothesListShortage.Count > 0)
Console.WriteLine("We are short of shoes");
Console.ReadLine();
}
static void AnonMethod(List<string> list)
{

List<string> evenNumbers =
list.FindAll(delegate(string i)
{ return (i.Length % 2) == 0; });
foreach (string evenNumber in evenNumbers)
{
Console.WriteLine(evenNumber);
}
}
static void LambdaExample(List<string> list)
{
var evenNumbers = list.FindAll(i =>
(i.Length % 2) == 0); // example of single parameter
foreach(string i in evenNumbers)
{
Console.WriteLine(i);
}
}
}
public static class Extensions
{
public static Dictionary<K, V> FilterBy<K, V>
(this Dictionary<K, V> items, KeyValueFilter<K, V> filter)
{
var result = new Dictionary<K, V>();
foreach(KeyValuePair<K, V> element in items)
{
if (filter(element.Key, element.Value))
result.Add(element.Key, element.Value);
}
return result;
}
}
}

The second technique is sort of interesting. It filters the list of strings based on the length of the string, but it uses a new syntax. If you have Visual Studio 2005 and LinQ Preview installed, you can use the editor to compile the application. If you do not have VS2005, you can compile the code from the command line by using the following command:

C:\Program Files\LINQ Preview\Bin\Csc.exe
/reference:"C:\Program Files\LINQ Preview\Bin\System.Data.DLinq.dll"
/reference:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Data.dll
/reference:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.dll
/reference:"C:\Program Files\LINQ Preview\Bin\System.Query.dll"
/reference:C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll
/reference:"C:\Program Files\LINQ Preview\Bin\System.Xml.XLinq.dll"
/target:exe Program.cs

The New Lambda Expressions Feature in C# 3.0
By Vipul Patel

Go to page: Prev 1 2

Inside the Intermediate Language (IL)

To get under the hood of the code, fire up ILDASM and select the application. You will see something similar to the screenshot in Figure 1.



Click here for a larger image.

Figure 1: Sample Application in ILDASM

Double-click the AnonMethod function to see the IL generated by the C# compiler:

.method private hidebysig static void AnonMethod(class [mscorlib]System.Collections.Generic.List`1<string> list) cil managed { // Code size 96 (0x60) .maxstack 4 .locals init ([0] class [mscorlib]System.Collections.Generic.List `1<string> evenNumbers, [1] string evenNumber, [2] valuetype [mscorlib]System.Collections.Generic.List `1/Enumerator<string> CS$5$0000, [3] bool CS$4$0001) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldsfld class [mscorlib]System.Predicate `1<string> LambdaExample.Program:: `<>9__CachedAnonymousMethodDelegate1' IL_0007: brtrue.s IL_001c IL_0009: ldnull IL_000a: ldftn bool LambdaExample.Program:: `<AnonMethod>b__0'(string) IL_0010: newobj instance void class [mscorlib]System.Predicate `1<string>::.ctor(object, native int) IL_0015: stsfld class [mscorlib]System.Predicate`1<string> LambdaExample.Program:: `<>9__CachedAnonymousMethodDelegate1' IL_001a: br.s IL_001c IL_001c: ldsfld class [mscorlib]System.Predicate`1<string> LambdaExample.Program::'<> 9__CachedAnonymousMethodDelegate1' IL_0021: callvirt instance class [mscorlib]System.Collections. Generic.List`1<!0> class [mscorlib]System. Collections.Generic.List`1<string>:: FindAll(class [mscorlib]System.Predicate`1<!0>) IL_0026: stloc.0 IL_0027: nop IL_0028: ldloc.0 IL_0029: callvirt instance valuetype [mscorlib]System.Collections. Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1 <string>::GetEnumerator() IL_002e: stloc.2 .try { IL_002f: br.s IL_0042 IL_0031: ldloca.s CS$5$0000 IL_0033: call instance !0 valuetype [mscorlib]System. Collections.Generic.List`1/Enumerator <string>::get_Current() IL_0038: stloc.1 IL_0039: nop IL_003a: ldloc.1 IL_003b: call void [mscorlib]System.Console:: WriteLine(string) IL_0040: nop IL_0041: nop IL_0042: ldloca.s CS$5$0000 IL_0044: call instance bool valuetype [mscorlib]System. Collections.Generic.List`1/Enumerator <string>::MoveNext() IL_0049: stloc.3 IL_004a: ldloc.3 IL_004b: brtrue.s IL_0031 IL_004d: leave.s IL_005e } // end .try finally { IL_004f: ldloca.s CS$5$0000 IL_0051: constrained. valuetype [mscorlib]System.Collections. Generic.List`1/Enumerator<string> IL_0057: callvirt instance void [mscorlib]System. IDisposable::Dispose() IL_005c: nop IL_005d: endfinally } // end handler IL_005e: nop IL_005f: ret } // end of method Program::AnonMethod

Now see the IL generated by the LambdaExample function. It is strikingly similar to the code generated by the LambdaExample method:

.method private hidebysig static void LambdaExample(class [mscorlib]System.Collections.Generic.List`1<string> list) cil managed { // Code size 96 (0x60) .maxstack 4 .locals init ([0] class [mscorlib]System.Collections.Generic.List`1<string> evenNumbers, [1] string i, [2] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string> CS$5$0000, [3] bool CS$4$0001) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldsfld class [mscorlib]System.Predicate`1<string> LambdaExample.Program::'<>9__CachedAnonymousMethodDelegate5' IL_0007: brtrue.s IL_001c IL_0009: ldnull IL_000a: ldftn bool LambdaExample.Program::'<LambdaExample>b__4'(string) IL_0010: newobj instance void class [mscorlib]System.Predicate`1<string>::.ctor(object, native int) IL_0015: stsfld class [mscorlib]System.Predicate`1<string> LambdaExample.Program::'<>9__CachedAnonymousMethodDelegate5' IL_001a: br.s IL_001c IL_001c: ldsfld class [mscorlib]System.Predicate`1<string> LambdaExample.Program::'<>9__CachedAnonymousMethodDelegate5' IL_0021: callvirt instance class [mscorlib]System.Collections.Generic.List`1<!0> class [mscorlib]System.Collections.Generic.List`1<string>::FindAll(class [mscorlib]System.Predicate`1<!0>) IL_0026: stloc.0 IL_0027: nop IL_0028: ldloc.0 IL_0029: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator() IL_002e: stloc.2 .try { IL_002f: br.s IL_0042 IL_0031: ldloca.s CS$5$0000 IL_0033: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::get_Current() IL_0038: stloc.1 IL_0039: nop IL_003a: ldloc.1 IL_003b: call void [mscorlib]System.Console::WriteLine(string) IL_0040: nop IL_0041: nop IL_0042: ldloca.s CS$5$0000 IL_0044: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::MoveNext() IL_0049: stloc.3 IL_004a: ldloc.3 IL_004b: brtrue.s IL_0031 IL_004d: leave.s IL_005e } // end .try finally { IL_004f: ldloca.s CS$5$0000 IL_0051: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string> IL_0057: callvirt instance void [mscorlib]System.IDisposable::Dispose() IL_005c: nop IL_005d: endfinally } // end handler IL_005e: nop IL_005f: ret } // end of method Program::LambdaExample

From the code listing above, you can deduce that the anonymous method and the lambda expression essentially compile to the same IL internally. Hence, their executions are similar.

Lambda Expressions with Multiple Parameters

Lambda expressions can take up multiple parameters. For example, say you have a Dictionary containing the information in Table 1.

Clothing TypeCountShirts15Jeans12Shoes9Pajamas9

Table 1: Information in Dictionary

If you have an anonymous method (FilterBy) to filter the dictionary by key and value, you can call that anonymous method through lambda expressions passing multiple parameters. The accompanying source code has the implementation of FilterBy:

var ClothesListShortage = clothesList.FilterBy((string name, int count) => name == "Shoes" && count < 10);

Simpler Syntax

Lambda expressions provide a simple way to write inline code blocks where delegates are expected. Their behavior is strikingly similar to anonymous methods. In fact, they are syntactic sugar in terms of syntax. They can take multiple parameters, explicit or implicit.

Download the Code

You can download the code that accompanies the article here.



Mr.Novice
What exactly are lambda expressions in C#?

I while ago I watched a very interesting Channel 9 video with Erik Meijer and Charles Torre. The video is about functional programming and why that is important in the multi-core world. They talk also about LINQ and lambda expressions and by the end of the video Erik mentions that he often gets the question about what lambda expression exactly are (in C#). So what are they?

To understand that we should probably go a little bit back in time. Let’s go back to the time of .NET 1.0 (C# 1.0) and start with the concepts of delegates. Delegates are a concept that wasn’t completely new with the advent of .NET. It was there before and for example in C++ they were called “function pointer”, which is probably more clear about what they do: a delegate holds a reference to a function (or method; whatever you like more) and allows you to call that function later on in time.

In .NET they renamed the concept to “delegate” and added type-safety to it. That means you have to exactly specify in the delegate what result type you expect and how many arguments and of what type you expect. After that you can use your delegate to point it to a method that has the specified signature; if you try to point it to a method with another signature you will get a compiler error, which is good! You can then pass the method around as if it is a variable:

internal sealed class Program
{
// Definition of the delegate.
public delegate void MyCoolDelegate(string arg);

static void Main(string[] args)
{
// create the delegate and point it to the "PrintToConsole" method.
MyCoolDelegate myCool = new MyCoolDelegate(PrintToConsole);

// invoke the delegate.
myCool(“Test”);
}

public static void PrintToConsole(string value)
{
Console.WriteLine(value);
}
}

A delegate is just a reference to a method that you can use as if it is a variable. You can pass it to methods and invoke it whenever you think it is required. Delegates are a powerful concept because now not only variables are data, but also functions/methods can be threaten as if they are data. Functions have become first class citiziens.

Let’s fast forward little bit and stop at the time when .NET 2.0 and C# 2.0 were released. For C# 2.0 the C# team added something very nice and useful: anonymous delegates or better known as anonymous methods.

The difference between anonymous methods and traditional delegates (as in .NET 1.0) is only that you don’t need to define a method somewhere else and point to it with a delegate to do the job. You directly define the method where you would create the delegate and the C# compiler will take care of it. The C# compiler will create the method for you and convert it into something that looks exactly like in .NET 1.0.

Let’s compare the tranditional delegate and anonymous method ways:

// — the traditional way.
internal sealed class Program
{
static void Main(string[] args)
{
// create a list with some data.
List<string> list = new List<string>();
list.Add(“value1″);
list.Add(“value2″);

// find in the list. We need to specify a method here
// that does the logic to find the data we need.
string result = list.Find(new Predicate<string>(FindInList));
}

// This method finds the data in the list.
static bool FindInList(string value)
{
return (value == “value2″);
}
}

// — the anonymous method
internal sealed class Program
{
static void Main(string[] args)
{
// create a list with some data.
List<string> list = new List<string>();
list.Add(“value1″);
list.Add(“value2″);

// find in the list by using an anonymous method.
string result = list.Find(delegate(string value)
{
return (value == “value2″);
});
}
}

You can clearly see the difference here. With the anonymous method we don’t need to create another method and a delegate that points to that method. We just say that we want to use a delegate here and specify the body of the method. It’s much more convenient to use an anonymous method instead of the traditional delegate way. The reason for that is that the code that belongs together stays together.

Another nice feature that has been introduced with anonymous methods is the possiblity to use variables that are defined outside of the method inside the method:

static void Main(string[] args)
{
// create a list with some data.
List<string> list = new List<string>();
list.Add(“value1″);
list.Add(“value2″);

string toFind = “value2″;

// find in the list. We need to specify a method here
// that does the logic to find the data we need.
string result = list.Find(delegate(string value)
{
return (value == toFind);
});
}

In the example you can see that I use the “toFind” variable inside the delegate body although it is defined outside of it. That’s some magic that is done by the C# compiler: in this case the C# compiler doesn’t only create a method for us but a whole class (that contains the method) where the value that we use in the body is passed in as class member. That is why we can access the value inside of the method body: as class member it is part of the class and you have access to the class members from inside a method.

Now let’s move on to the present day and C# 3.0 (and .NET 3.5) and speak about lambda expressions. Lambda expression are just the next step in the “delegate evolution”. The compiler now even hides away the whole “delegate(…) { … }”. It’s is very convenient because that saves us a lot of typing!

A lambda expression always consists of a left and a right part. The left part is on the left side of the “=>” and the right part is on the right side of it. The left part holds the list of arguments, where we even don’t need to specify the types because they can be automatically fetched by the compiler. The right side contains the body of the method. A lambda expression always expects us to return some value that is why we can also omit the “return” keyword:

static void Main(string[] args)
{
// create a list with some data.
List<string> list = new List<string>();
list.Add(“value1″);
list.Add(“value2″);

string toFind = “value2″;

// find in the list. We need to specify a method here
// that does the logic to find the data we need.
string result = list.Find(value => toFind == value);
}

To sum it up: lambda expressions are just delegates (or type-safe “function pointers”). They only look as they are because some assumptions are taken (like a lambda expression are functions and therefore always returns a value) and the types can be automatically fetched by the compiler. The nice side effect is that lambda expressions save us a lot of typing and time.


Mujahid Khaleel
Lambda expression

A lambda expression is shorthand for anonymous method. Like anonymous method, lambda expression is assigned to delegate types. All conditions that apply for anonymous methods also apply to lambda expressions.

http://www.mujahiddev.com/2009/01/lambda-expressions-c.html


Page view tracker