Lambda Expressions (C# Programming Guide)
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:
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:
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<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 sixteen 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).
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 (C# and Visual Basic). 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:
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:
Specify zero input parameters with empty parentheses:
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.
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.
Many Standard query operators have an input parameter whose type is one of the Func<T, TResult> family of generic delegates. The Func<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:
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:
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:
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 (>=).
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# 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:
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.
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.
For more information, see the C# Language Specification. The language specification is the definitive source for C# syntax and usage.
- 4/30/2012
- A. Hagel
http://planetofcoders.com/c-lambda-expressions/
- 3/9/2012
- Gaurav_Agrawal
- 1/18/2012
- Jet Propulsion
I am not employed to write clever code. I am employed to write transparent, maintainable code for those that follow when I am gone.
Ultimately clever code is a false economy, and Lambdas sit right in that falsehood.
- 1/10/2012
- JimsShed
Finally, as you can hopefully see, the final implementation is simple, quite easy to quickly understand and with the ability of lambdas to capture local variables, in this case, the arguments to the indexers, all the delegate needed as an argument was the car we are testing. Doing something like this with a purely iterative approach is much much uglier IMHO.
public class Show_Room : LinkedList<Car>
{
private delegate bool Predicate(Car a);
public List<Car> this[string make]
{
get
{
return doSearch(car => car.Make.ToLower() == make.ToLower());
}
}
public List<Car> this[double price]
{
get
{
return doSearch(car => car.Price == price);
}
}
public List<Car> this[DateTime year, string model]
{
get
{
return doSearch(car => car.Date_Made.Year == year.Year && car.Model.ToLower() == model.ToLower());
}
}
public List<Car> this[double price, int qty]
{
get
{
return doSearch(car => car.Price == price && car.In_Stock == qty);
}
}
private List<Car> doSearch(Predicate pred)
{
var results = from c in this
where pred(c)
orderby c.Price
select c;
if (results.Count() == 0)
throw new CarNotFoundException();
return results.ToList();
}
}
- 11/9/2011
- Michael AD Brown
- 11/9/2011
- Michael AD Brown
Lambda expressions capture extra this pointer, if lambda use local variable and static variable or method, and delegate created from instance method in the same method as lambda expression.
using System;
internal static class Test{
private static void Main(){
try{
Console.WriteLine("{0,10}: Start point",GC.GetTotalMemory(true));
LambdaTest1 test1=new LambdaTest1();
Console.WriteLine("{0,10}: LambdaTest1 created",GC.GetTotalMemory(true));
Func<int> func1=test1.GetFunc();
Console.WriteLine("{0,10}: LambdaTest1 GetFunc called",GC.GetTotalMemory(true));
GC.KeepAlive(test1);
test1=null;
Console.WriteLine("{0,10}: LambdaTest1 removed, memory freed",GC.GetTotalMemory(true));
GC.KeepAlive(func1);
func1=null;
Console.WriteLine("{0,10}: LambdaTest1 func removed",GC.GetTotalMemory(true));
LambdaTest2 test2=new LambdaTest2();
Console.WriteLine("{0,10}: LambdaTest2 created",GC.GetTotalMemory(true));
Func<int> func2=test2.GetFunc();
Console.WriteLine("{0,10}: LambdaTest2 GetFunc called",GC.GetTotalMemory(true));
GC.KeepAlive(test2);
test2=null;
Console.WriteLine("{0,10}: LambdaTest2 removed, memory not freed",GC.GetTotalMemory(true));
GC.KeepAlive(func2);
func2=null;
Console.WriteLine("{0,10}: LambdaTest2 func removed, memory freed",GC.GetTotalMemory(true));
}catch(Exception e){
Console.WriteLine(e);
}
Console.ReadKey(true);
}
private class LambdaTest1{
private static int staticI=1;
private byte[] data=new byte[100000000];
private void Instance(){}
internal Func<int> GetFunc(){
int localI=2;
//Action action=Instance;
return ()=>localI+staticI;
}
}
private class LambdaTest2{
private static int staticI=1;
private byte[] data=new byte[100000000];
private void Instance(){}
internal Func<int> GetFunc(){
int localI=2;
Action action=Instance;
return ()=>localI+staticI;
}
}
}
- 9/5/2011
- PetSerAl
Why Lambda?
Lambda Expressions can solve problems in varying ways. One very limited example is this... You can utilize them to define logical parts and reuse them later. If done well this can make the code that uses the defined expressions more readable...
Pretend this is contained in a library written by Lambda aware folks and provided to the front end team.
Func<string,string> safe = t => {
if( String.IsNullOrWhitespace(t) ){
return String.Empty;
}else{
return t;
}
};
...and in our front side
Person person = new Person {
FirstName = safe( recordSet["FirstName"]),
LastName = safe( recordSet["LastName"]),
...
};
...instead of what I see commonly:
Person person = new Person();
person.FirstName = String.IsNullOrWhiteSpace(recordSet["FirstName"]) ? String.Empty : recordSet["FirstName"];
person.LastName = String.IsNullOrWhiteSpace(recordSet["FirstName"]) ? String.Empty : recordSet["FirstName"];
This is, admittedly, a bit of a silly example but it's a quick demonstration of how small, but repetitive logic could be cleaned up using a couple simple Lambda expression. One side affect here is that if I every wanted to change the global default for an application I could in a single line instead of multiple places in the code.
*Lambda Expressions come from Lambda Calculus and were not invented by Microsoft just to confuse and fuddle developers who never learned more than simple imperative programming.
- 9/1/2011
- William Bellman
with lambda expressions, code can become compact, that inturn can make things eazier. For example I remember I once did a very complicated Grouping using Aggregate<> and lambda expressions, and the code was only 1 line to maintain. This single line could eazily beocme a project in itself, giving more than 300 lines of C# code to maintain. Its always right tool for right work that we have to pick carefully.
KS
- 8/19/2011
- Kranthi Sukka
Let's say that you have a varible ListOfWidgets defined as List<Widget> and you want to find a Widget with a specific WidgetId. This is how I would use it.
public Widget GetWidget(int widgetId)
{
return ListOfWidgets.Find(rec => rec.WidgetId == widgetId);
}
This is very simple and should be relatively easy to understand. It was hard to get used to the syntax, but for simple cases like these the one line of code rather than a for loop with an if condition actually is quicker to write and it is still easy to understand (for me at least).
- 8/12/2011
- Gerry Cox
C# compiler generate code what capture extra local variables:
using System;
using System.Collections.Generic;
using System.Linq;
internal static class Test{
private static Random random=new Random();
private static void Main(){
try{
Func<IEnumerable<byte>>[] array=new Func<IEnumerable<byte>>[1024];
for(int i=0;i<1024;++i){
Func<IEnumerable<byte>> ab,bc,ca;
F(out ab,out bc,out ca);
array[i]=ab;
}
Console.WriteLine(GC.GetTotalMemory(true));
GC.KeepAlive(array);
}catch(Exception e){
Console.WriteLine(e);
}
Console.ReadKey();
}
private static void F(out Func<IEnumerable<byte>> ab,out Func<IEnumerable<byte>> bc,out Func<IEnumerable<byte>> ca){
byte[] a=new byte[1024];
random.NextBytes(a);
byte[] b=new byte[1024];
random.NextBytes(b);
byte[] c=new byte[1024*1024];
random.NextBytes(c);
ab=()=>a.Concat(b);
bc=()=>b.Concat(c);
ca=()=>c.Concat(a);
}
}
C# compiler rewrite code like this:
using System;
using System.Collections.Generic;
using System.Linq;
internal static class Test{
private static Random random=new Random();
private static void Main(){
try{
Func<IEnumerable<byte>>[] array=new Func<IEnumerable<byte>>[1024];
for(int i=0;i<1024;++i){
Func<IEnumerable<byte>> ab,bc,ca;
F(out ab,out bc,out ca);
array[i]=ab;
}
Console.WriteLine(GC.GetTotalMemory(true));
GC.KeepAlive(array);
}catch(Exception e){
Console.WriteLine(e);
}
Console.ReadKey();
}
private static void F(out Func<IEnumerable<byte>> ab,out Func<IEnumerable<byte>> bc,out Func<IEnumerable<byte>> ca){
AnonymousClass1 anonymousClass1=new AnonymousClass1();
anonymousClass1.a=new byte[1024];
random.NextBytes(anonymousClass1.a);
anonymousClass1.b=new byte[1024];
random.NextBytes(anonymousClass1.b);
anonymousClass1.c=new byte[1024*1024];
random.NextBytes(anonymousClass1.c);
ab=anonymousClass1.LambdaExpression1;
bc=anonymousClass1.LambdaExpression2;
ca=anonymousClass1.LambdaExpression3;
}
private sealed class AnonymousClass1{
public byte[] a;
public byte[] b;
public byte[] c;
public IEnumerable<byte> LambdaExpression1(){
return a.Concat(b);
}
public IEnumerable<byte> LambdaExpression2(){
return b.Concat(c);
}
public IEnumerable<byte> LambdaExpression3(){
return c.Concat(a);
}
}
}
As you can see, "c" local variable was captured and preserved as part of AnonymousClass1 object, despite the fact that all delegates what use it are not preserved.
I am suggest to rewrite code like this:
using System;
using System.Collections.Generic;
using System.Linq;
namespace System{
public class CapturableLocalVariable<T>{
public T Value;
}
}
internal static class Test{
private static Random random=new Random();
private static void Main(){
try{
Func<IEnumerable<byte>>[] array=new Func<IEnumerable<byte>>[1024];
for(int i=0;i<1024;++i){
Func<IEnumerable<byte>> ab,bc,ca;
F(out ab,out bc,out ca);
array[i]=ab;
}
Console.WriteLine(GC.GetTotalMemory(true));
GC.KeepAlive(array);
}catch(Exception e){
Console.WriteLine(e);
}
Console.ReadKey();
}
private static void F(out Func<IEnumerable<byte>> ab,out Func<IEnumerable<byte>> bc,out Func<IEnumerable<byte>> ca){
CapturableLocalVariable<byte[]> a=new CapturableLocalVariable<byte[]>();
a.Value=new byte[1024];
random.NextBytes(a.Value);
CapturableLocalVariable<byte[]> b=new CapturableLocalVariable<byte[]>();
b.Value=new byte[1024];
random.NextBytes(b.Value);
CapturableLocalVariable<byte[]> c=new CapturableLocalVariable<byte[]>();
c.Value=new byte[1024];
random.NextBytes(c.Value);
ab=Tuple.Create(a,b).LambdaExpression1;
bc=Tuple.Create(b,c).LambdaExpression2;
ca=Tuple.Create(c,a).LambdaExpression3;
}
private static IEnumerable<byte> LambdaExpression1(this Tuple<CapturableLocalVariable<byte[]>,CapturableLocalVariable<byte[]>> context){
return context.Item1.Value.Concat(context.Item2.Value);
}
private static IEnumerable<byte> LambdaExpression2(this Tuple<CapturableLocalVariable<byte[]>,CapturableLocalVariable<byte[]>> context){
return context.Item1.Value.Concat(context.Item2.Value);
}
private static IEnumerable<byte> LambdaExpression3(this Tuple<CapturableLocalVariable<byte[]>,CapturableLocalVariable<byte[]>> context){
return context.Item1.Value.Concat(context.Item2.Value);
}
}
Now "c" local variable captured but not preserved (collected by garbage collector), as all delegate what use it not preserved in "Test.Main".
- 6/9/2011
- PetSerAl
- 6/2/2011
- NPSF3000
- 5/26/2011
- Chandrashekhar W
http://www.mindstick.com/Blog/181/Lambda%20Expression%20in%20c
This might be use ful.
- 5/23/2011
- Awadhendra Kumar Tiwari
Each one of us must individually decide whether to use it or not.
And I for one do not understand how a single line lambda expression is considered more readable than a simple while or for loop. May be in a couple of years both would mean the same to me but for now, I would stick on to the good 'ol 3 line forloop.
- 5/23/2011
- cethie
By far, the greatest costs associated with software are in development and maintenance. Do you really want that recursive lambda expression(s) for generating a simple factorial to be inserted in place of:
intfactorial(intn)
{
if(n<=1)
return1;
else
return n*factorial(n-1);
}
Just because you can do something doesn't mean you should. It reminds me of the old APL contest to see who could write the most obscure code for a specified function. In the end, this will be wiped into "frameworks" or forgotten altogether.
- 5/13/2011
- UsbHidNewbie
This belongs in framework and reusable component development, the kind of stuff that is rarely touched once it is created and tested.
And yes. If your standard for understandability is conditionals and loops only, please ignore this kind of stuff. Better still, stick to VB Script. ;)
- 5/11/2011
- Devaiah Kokkalemada
- 4/21/2011
- venk
One example that I can think of is that they are very useful for Execute Around pattern that Kent Beck described back in '97. That alone would be enough ,but there is much more to it than just that.
- 3/27/2011
- Kresimir Bojcic
- 3/27/2011
- Kresimir Bojcic
E.g. given a list of strings that might contain duplicates when case sensitivity is ignored, find all duplicate values. A procedural approach isn't complicated but would mean writing the iteration code and building up the list of results. The lambda approach defines an expression to return these by specifying just the logical test, not the iteration.
This might be a trivial example but the benefit grows as the problem gets more intricate. If unconvinced then do check out Jon Skeet's C# In Depth (which is well worth the effort anyway).
- 3/23/2011
- AndrewTRichards
Lambdas are, in my opinion, vital to making decent programs that handle much data, like lists. They need sorting, you might need to pick some members and move them to another list, etc. Plus, you really don't have to use them if you don't have to.
I personally find them a very good addition to the .NET languages.
- 3/20/2011
- Vercas
To the poster who wrote that as professionals, we need to learn new technology and adapt: I agree. But we also need the experience and wisdom to avoid jumping on every bandwagon that rolls through town. Especially those with loose wheels and no sign of a competent driver.
- 3/15/2011
- Marc Aaron
- 2/24/2011
- kjmcsd.net
- 2/9/2011
- jacobUT
- 1/19/2011
- Ken Varn
They are very hand, too. They let you create delegates with fewer lines of code, for one thing. Fewer lines of code means fewer opportunities for mistakes and greater productivity. They are also key to the LINQ technology, which, again, lets you do more with less effort. In LINQ and elsewhere, Lambda expressions are a standard way to express almost any kind of query, without having to invent your own classes to do so.
If you want everything to be "simple" then go back to programming in C. And forget about the .NET Framework because it's waaaay harder to master than C's good old standard libraries. Throw out Windows and Web programming and go back to DOS, where you could always control what was going to happen next.
But if your goal is to be a true professional, then you must master the tools of your trade ... and stay up-to-date. Doctors must keep up with the latest medical advances, auto mechanics must study up on the latest innovations from Detroit and Japan, and we programmers must put in the time to master the language innovations that will increase our productivity. If you don't do it, there are plenty of people around the world who would love to take your place.
Besides, if you don't get pleasure out things like Lambdas, why are you even in this profession? To me, they are elegant and fun.
- 1/10/2011
- LSpencer