DaedTech

Stories about Software

By

Introduction to C# Lambda Expressions

Today, I’m going to post an excerpt of a tutorial I created for the use of Moq on an internal company wiki for training purposes. I presented today on mocking for unit tests and was revisiting some of my old documentation, which included an introductory, unofficial explanation of lambda expressions that doesn’t involve any kind of mathematical lingo about lambda calculus or the term “first class functions”. In short, I created this to help someone who’d never or rarely seen a lambda expression understand what they are.

Lambdas


Since Moq makes heavy use of lambda expressions, I’ll explain a bit about how those work here. Lambdas as a concept are inherently highly mathematical, but I’ll try to focus more on the practical aspects of the construct as they relate to C#.

In general, lambda expressions in the language are of the form (parameters) => (expression). You can think of this as a mapping and we might say that the semantics of this expression is “parameters maps to expression”. So, if we have x => 2*x, we would say “x maps to two times x.” (or, more generally, number maps to number).

In this sense, a lambda expression may be thought of in its most practical programming sense as a procedure. Above, our procedure is taking x and transforming it into 2*x. The “maps to” semantics might more colloquially be called “becomes”. So, the lambda expression x => 2*x translates to “x becomes 2 times x.”

Great. So, why do this? Well, it lets you do some powerful things in C#. Consider the following:

public List FilterOut(List list, int target)
{
  var myList = new List();
  foreach(int myValue in list)
  {
    if(myValue != target)
    {
       myList.Add(myValue);
    }
  }
  return myList;
}

public void SomeMethod(List values)
{
  var myNewList = FilterOut(values, 6);  //Get me a list without the sixes.
}

Here, we have a function that will filter an int value out of a list. It’s a pretty handy function, since it lets you pick the filter value instead of, say, filtering out a hard-coded value. But, let’s say some evil stakeholder comes along and says “well, that’s great, but I want to be able to filter out two values. So, you add a method overload that takes two filters, and duplicate your code. They then come along and say that they want to be able to filter out three values, and they also want to be able to filter out values that are less than or greater than a specified value. At this point, you take a week off because you know your code is about to get really ugly.

Except, lambda expressions to the rescue! What if we changed the game a little and told the stakeholder, “hey, pass in whatever you want for criteria.”

public List FilterOut(List list, Func<int, bool> filterCriteria)
{
  var myList = new List();
  foreach(int myValue in list)
  {
    if(!filterCriteria(myValue))
    {
      myList.Add(myValue);
    }
  }
  return myList;
}

public void SomeMethod(List values)
{
  var myNewList = FilterOut(values, x => x == 6);  //Get me a list without the sixes.
  myNewList = FilterOut(values, x => x == 6 || x == 7); //Get me a list without six or seven.
  myNewList = FilterOut(values, x => x > 6 && x < 12); //Get me a list with no values between 7 and 11.
 //... and anything else you can think of that takes an integer and returns a boolean
}

Now, you don’t have to change your filter code at all, no matter what the stakeholder asks for. You can go back and say to him, “hey, do whatever you want to that integer — I don’t care”. Instead of having him pass you an integer, you’re having him pass you something that says, “integer maps to bool” or “integer becomes bool”. And, you’re taking that mapping and applying it to each element of the list that he’s passing you. For elements being filtered out, the semantics is “integer becomes false” and for elements making the cut “integer becomes true”. He’s passing in the mapping, and you’re doing him the service of applying it to the elements of the list he’s giving you.

In essence, lambda expressions and the mappings/procedures that they represent allow you to create algorithms on the fly, ala the strategy design pattern. This is perfect for writing code where you don’t know exactly how clients of your code want to go about mapping things — only that they do.

As it relates to Moq, here’s a sneak peak. Moq features expressions like myStub.Setup(mockedType => mockedType.GetMeAnInt()).Returns(6);
What this is saying behind the scenes, is “Setup my mock so that anyone who takes my mocked type and maps it to its GetMeAnInt() method gets a 6 back from it” or “Setup my mock so that the procedure MockedType.GetMeAnInt() returns 6.”

(By the way, the link I used for the visual is from this post, which turned out to be a great find. RSS feed added to my reader.)

By the way, if you liked this post and you're new here, check out this page as a good place to start for more content that you might enjoy.
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
.Net Training in Chennai

C# supports two types of lambda expressions:

1. Expression Lambda
If the lambda body consists of a single expression, then an expression lambda is being created.
2. Statement lambda
If the lambda body contains two or more statements enclosed by braces, then a statement lambda is being created.

geetha
geetha
7 years ago

Nice post.