Skip to Content
Course content

48: Lambda Expressions in C#

Click on the "Edit" button in the top corner of the screen to edit your slide content.

You've likely seen the => operator in C# and thought, "Okay, this is just a shortcut for writing a small method." It's a common assumption because, on the surface, that's exactly what it looks like. But here is where the misconception trips people up: they think a lambda expression is a *type* of function you define independently.

If you try to just drop a lambda expression into the middle of a class like this:

public class OrderProcessor 
{
    // This will not compile!
    (int price) => price * 1.10m; 
}

The compiler will scream at you. Why? Because a lambda expression isn't a method; it's an anonymous function that is treated as data. It has no name and no place to live until you assign it to a delegate. In my experience, the "aha!" moment happens when you stop thinking of lambdas as "small methods" and start thinking of them as "logic that can be passed around as a variable."

The Delegate is the Bucket

To use a lambda, you need a "bucket" to hold it. In C#, those buckets are usually Func<...> or Action<...>. If your lambda returns a value, use Func. If it just performs a task and returns nothing (void), use Action.

Let's look at a real-world scenario. Imagine you're building a system to validate user passwords. Instead of writing ten different methods for ten different rules, you can treat the rules as data:

// Func<Input, Output>
// This bucket takes a string and returns a bool
Func<string, bool> isLongEnough = (password) => password.Length >= 8;
Func<string, bool> hasNumber = (password) => password.Any(char.IsDigit);

bool isValid = isLongEnough("Secret123") && hasNumber("Secret123");

I love this approach because it makes your code incredibly flexible. You can now put these Func objects into a List<Func<string, bool>> and loop through them, rather than hard-coding a massive chain of if statements.

Passing Logic into LINQ

You'll most frequently encounter lambdas when using LINQ. When you call .Where() or .Select(), you aren't passing a value to the method; you're passing a formula that the method will apply to every item in the collection.

Consider a list of Product objects. If you want to find all products that are both "Electronics" and cost more than $500, you don't write a loop. You pass a lambda that describes the criteria:

var expensiveElectronics = products.Where(p => p.Category == "Electronics" && p.Price > 500);

Read that p => ... as "for each element p, return true if this condition is met." The Where method handles the looping; your lambda provides the intelligence.

Capturing the Surroundings

One of the most powerful (and sometimes dangerous) features of lambdas is their ability to "capture" variables from the scope where they are defined. This is called a closure.

Suppose you have a threshold value that changes based on user settings. You can bake that variable directly into your lambda:

decimal userPriceThreshold = 100.00m; 
// The lambda "captures" userPriceThreshold from the outside
var affordableItems = products.Where(p => p.Price < userPriceThreshold);

The lambda doesn't just take the value of the threshold at the moment it was created; it keeps a reference to the variable itself. If userPriceThreshold changed before the Where clause actually executed, the lambda would use the updated value. Just be careful with this in asynchronous code, or you'll find yourself chasing ghosts in your debugger.




📋 Practical Task

Building a Dynamic Discount Engine

You are tasked with creating a flexible discount system for a shopping cart. Instead of hard-coding discounts, you need to create a system that can accept different "discount rules" as lambdas.

Requirements:

  • Create a Product class with Name (string) and Price (decimal).
  • Create a List<Product> containing at least 4 items (e.g., "Laptop" at 1200, "Mouse" at 25, "Keyboard" at 80, "Monitor" at 300).
  • Define a Func<Product, decimal> called discountRule.
  • Assign a lambda to discountRule that applies a 10% discount if the product price is over 100, otherwise no discount.
  • Use a foreach loop to print each product's name and its final price after applying the discountRule.
  • Bonus: Change the discountRule lambda to a different rule (e.g., a flat $20 off for everything) and verify that the same loop now produces different results without changing the loop logic itself.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.