Lambdas? That’s a frat right? Why are they in C#?
No no… it’s not a frat! Lambdas are simply a syntax that we use to define anonymous methods. What’s an anonymous method? It’s a method that has no declaration. What’s a method declaration? Jeez man…
Method Anatomy
1 2 3 4 |
public void DoStuff(int input) { Console.WriteLine("The number is {0}", input); } |
That is a method declaration. But to understand lambdas, let’s look at this method declaration and break it apart first.
1 |
public void DoStuff(int input); |
The first part of a method is the signature. It is made up of the access modifier, the return type, the method name, and then the parameter list.
Then, of course, everything between { and } is the body of the method; the series of expressions (aka a statement) that will be executed when the method is run. A lambda is exactly this, but without all the fluff. Let’s look at this method again, but this time, I will cross out all of the things that a lambda doesn’t need as a method:
There you have it! Lambdas are just methods without the access modifier, return type, name, or body braces (although you’ll need the braces still if you wanna use more than a single expression…). So if you cut out all of that, here’s what you’re left with:
1 |
input => Console.WriteLine("The number is {0}", input) |
That, ladies ‘n gents is a lambda expression. A really simple lambda expression, but one nonetheless. The operator =>
is pronounced “goes to”. What it means is that whatever variables you declare on the left will be sent to the function on the right (e.g. “input goes to Console.WriteLine(“The number is {0}”, input)” )
Where to use Lambdas
Since lambdas are actually anonymous methods, you cannot just drop a lambda any-ole-where. You need to use them as delegates. If you don’t know what delegates are or what there used for, a) shame on you and b) let us know in the comments and we’ll get another article out that talks about delegates. Anyway, delegates — Most of the time in .Net, you’ll see delegates displayed as Action<T> or Func<T> in parameter lists:
1 2 3 4 5 |
public void DoAction(Action<string> action) { var myString = "Hello World"; action(myString); } |
This method requires an Action<string> parameter. That is, *a delegate that takes a single string parameter and returns nothing*. If you wanted it to be a method that takes two string parameters and returns nothing, then it would be Action<string, string>. If you wanted it to be a method that takes an int and a string and returns nothing, it would be Action<int, string>. Or maybe a method that takes an int and returns a string, it would be Func<int, string>. See how that works now?
An Action has zero or more parameters and returns nothing (void); a Func has zero or more parameters and returns something.
So now that we understand what this method is asking of us, how do we use it? Well you *could* send in a void method that matches the signature as a function pointer like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public void Main() { DoAction(MyMethod); } public void MyMethod(string input) { Console.WriteLine("The string is {0}", input); } public void DoAction(Action<string> action) { var myString = "Hello World"; action(myString); } |
But what if you didn’t want to have to declare the MyMethod method? Well that’s where lambdas come in. Send it in as an anonymous method in lambda syntax like so:
1 2 3 4 5 6 7 8 9 10 |
public void Main() { DoAction(myString => Console.WriteLine("The string is {0}", myString)); } public void DoAction(Action action) { var myString = "Hello World"; action(myString); } |
Why would I bother with this?
At this point, this is probably *almost* making sense. What is going on in here?
Well again, if you don’t understand delegates, you might wanna go brush up on what those are, but here’s my brief explanation.
Delegates are like variables for methods/functions. Just as you can assign int x = 10;
, you can assign Action x = () => DoStuff();
and pass those things around. But why would you want to do that? Well in this example, I use delegates as a way of delaying an operation. My DoAction
method will do something, and then run the action with whatever result it comes up with. So here’s a slightly more complete example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
public void Main() { var me = new Person("Jeremy", 10.00M); // normal day TakeBusToWork(me, person => person.GetDressedForWork()); // casual day TakeBusToWork(me, person => person.DressCasualForWork()); } public void TakeBusToWork(Person person, Action<Person> action) { Console.WriteLine("Preparing to take the bus..."); // maybe some other work here... // run delayed logic action(person); person.MoneyInPocket -= 1.5M; Console.WriteLine("Headed to work!\r\n"); } public class Person { public string Name { get; set; } public bool IsDressedForWork { get; set; } public decimal MoneyInPocket { get; set; } public Person(string name, decimal moneyInPocket) { Name = name; MoneyInPocket = moneyInPocket; } public void GetDressedForWork() { Console.WriteLine("Getting dressed for work..."); IsDressedForWork = true; Console.WriteLine("Collared shirt and slacks is engage!"); } public void DressCasualForWork() { Console.WriteLine("Getting dressed for work..."); IsDressedForWork = true; Console.WriteLine("I'm wearing pants...good enough!"); } } |
This isn’t he most real world practical example, but you still can see the point. I used the same method to take the bus to work for two different scenarios. The TakeBusToWork() algorithm was this:
- Let us know what is happening
- Maybe do some other prep work
- Run the action that was provided to us
- Take some money from the guy
- Let us know that you’re on your way to work
So the variable here was what to do in preparation to go to work. We decided ahead of time that the logic for such a thing could change, so instead of hard-coding it, we took a delegate as a parameter and executed it when it needed to be executed which was right in the middle of a bunch of other stuff.
So, this isn’t an example specifically for lambdas, but rather an example for delegation. However, by using a lambda as a delegate, we avoided having to declare 2 different methods to use as function pointers. Syntactical sugar, my friend. Om nom.
You can use lambda syntax when declaring event handlers as well! Now go try it — don’t forget to try it with functions (Func<T>)!