Using Lambda Expressions

The previous section showed you how to create lambda expressions in their simplest forms. What are they for, though? It was mentioned earlier that they are delegates and can be used anywhere delegates are used, but what exactly does that mean? The purpose of this section is to answer those questions by showing you how they can be used in practical situations.

Handling Events with Lambdas

One of the most common places that you will find lambda expressions being used is as event handlers. Chapter 3 covers events and event handlers in detail, but a simple definition is that they are delegates that are called when a particular event is fired.

The typical approach for handling events is to create a method that represents the handler and providing the address of it in the AddHandler statement.

AddHandler timer.tick, AddressOf TimerTickHandler
Private Sub TimerTickHandler(ByVal sender As Object, ByVal e As EventArgs)
    ' Handle the event
End Sub

Lambda expressions allow you to do this without having to create the named handler method. To see this in action, add the following code to your sample application:

Private Sub LambdaExpressionAsEventHandler()
    Dim timer As DispatcherTimer =
        New DispatcherTimer(Windows.Threading.DispatcherPriority.Normal)

    timer.Interval = TimeSpan.FromSeconds(5)
    AddHandler timer.Tick, Sub(source, args)
                               timer.Stop()
                               TextBoxResult.Text = "The timer has elapsed at " +
                                   DateTime.Now.ToLongTimeString()
                           End Sub

    timer.Start()
    TextBoxResult.Text = "Timer started at " + DateTime.Now.ToLongTimeString()
End Sub

Be sure to add the following statement at the top of the code file in order to use the DispatcherTimer class:

Imports System.Windows.Threading

This example creates a dispatch timer, a timer that runs using the dispatcher. You configured with a five-second interval so the Tick event will fire five seconds after the timer is started.

You need to handle the Tick event, so you use the AddHandler statement specifying the name of the event and your handler. In this case, you use a lambda expression to provide the handler rather than specifically making a method and using the AddressOf operator. The handler stops the timer and updates the results text box. The timer is started by calling the Start method. The timer itself runs in the background, so the main thread continues to execute.

To actually run this example, you need to add it to the examplesList collection by appending the following to the collection initializer:

New With {.Name = "Lambda Expression - Event Handler", _
          .Lambda = New Action(Sub() LambdaExpressionAsEventHandler())}

Run the application and select the new entry in the drop-down list. It will execute when you press the button. The first thing you will see is the message “Timer started at” followed by the current time. The timer is running in the background, so you just need to wait five seconds, after which the result window will be updating to look like Figure 5.4.

Figure 5.4 Event Handler example

5.4

Using lambda expressions as event handlers works just like you may be used to, but it can make the task a little easier and make the code flow a little more natural. An added bonus with using lambda expressions is that you can use variables that are in the scope of the parent method within the expression itself. You did this in the example when you used the timer variable to stop the timer.


Note
While lambda expressions are very powerful and useful, they can be abused. My personal experience has been that the contents of lambda expressions are short and concise. If you have a longer method, it most likely should be created as a method and called in the normal method. Also, try to constrain yourself on the amount of lambda expressions you use. You might be able to create an entire application from a single method that contains 50 lambda expressions, but it won't look very good or may not run very efficiently.

LINQ with Lambdas

Language Integrated Query (LINQ) allows you to create SQL-like queries against objects in code. You will not get into too much detail on what it is, since it is covered in great detail in Chapters 8 through 10, but certain points need to be understood in order for this to make the most sense.

LINQ queries typically rely on a set of clauses, such as Select and Where. These are key to supporting the SQL-like approach targeted by LINQ. What may not be obvious is that these clauses are just syntactic sugar that wraps extension methods of the IEnumerable(OF T) interface.

According to MSDN, the Where method (which corresponds to the Where clause) has the following declaration:

<ExtensionAttribute> _
Public Shared Function Where(Of TSource) ( _
       source As IEnumerable(Of TSource), _
       predicate As Func(Of TSource, Boolean) _
) As IEnumerable(Of TSource)

This is an extension method, so the first parameter is really the source collection that the method is being executed against. The second parameter is the one you are interested in. The Action delegate was mentioned in a previous section. Func(Of T, TResult) is also a delegate but differentiates itself from Action by allowing a return type, specified by the TResult parameter. As with the Action delegate, a lambda expression can be implicitly converted to a Func delegate.

All LINQ extension methods, and the clauses that wrap some of them, represent either an Action(Of T) or a Func(Of T, TResult). This means lambda expressions can be used to provide additional functionality and support to queries.

To experiment with this, you need to update your application with the following:

Private Sub LambdaExpressionsWithLinq()

    Dim fireFlyCrew =
        {
            New With {.Name = "Malcolm Reynolds", .Age = 31},
            New With {.Name = "Zoe Washburne", .Age = 30},
            New With {.Name = "Hoban Washburne", .Age = 31},
            New With {.Name = "Inara Serra", .Age = 27},
            New With {.Name = "Jayne Cobb", .Age = 40},
            New With {.Name = "Kaylee Frye", .Age = 23},
            New With {.Name = "Simon Tam", .Age = 25},
            New With {.Name = "River Tam", .Age = 19},
            New With {.Name = "Shepherd Book", .Age = 52}
        }

    Dim minimumAge = fireFlyCrew.Min(Function(crewMember) crewMember.Age)
    Dim youngest = From crewMember In fireFlyCrew
                   Where crewMember.Age = minimumAge

                   Select crewMember.Name

    TextBoxResult.Text = "The youngest crew member is " + youngest.First +
                         Environment.NewLine

    Dim averageAge = fireFlyCrew.Average(Function(crewMember) crewMember.Age)
    TextBoxResult.Text += "The average age is " + averageAge.ToString

End Sub

The first thing this method does is create a collection of anonymous types that have a Name and Age property. Next, you determine the youngest age and save it in the minimumAge variable. To calculate the minimum age you use the Min extension method, which accepts a Func(Of TSource, Integer) delegate. You use a lambda expression here, which is called for every record in the collection and provided with an instance of the anonymous type. The body of the expression is used within the actual calculation for determining the minimum.

If you just called Min() without providing an expression, you would receive an exception. That is because your anonymous type is not of a type, such as an Integer, that the function knows how to calculate. You overcome this by providing the function what it needs to execute correctly.

The example uses the minimum value within a query in order to get the name of the youngest person. You then perform a similar action by using the Average extension method as an additional test.

As with all the examples in this chapter, you can't actually test it until you add it to the list. Do this by updating the examplesList field, in the constructor, with the following item:

New With {.Name = "Lambda Expression - LINQ", _
          .Lambda = New Action(Sub() LambdaExpressionsWithLinq())}

When this example is executed (by selecting the name from the list and pressing the button) you will be presented with the appropriate results as shown in Figure 5.5.

Figure 5.5 LINQ example

5.5
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset