Showing posts with label LINQ. Show all posts
Showing posts with label LINQ. Show all posts

Monday, November 9, 2015

Reference Types, Value Types, and Equality

In many places, we don't need to worry about the difference between value types and reference types. But one place we do see a difference is how equality is handled by default. I've had a couple of questions and comments about this recently, so let's take a closer look.

The Question
The questions came from my video series on Lambdas and LINQ (video playlist). There's also a print article available for download here: Learn to Love Lambdas (and LINQ, Too!).

Here's the code we're looking at:


This code refreshes the data in a list box by calling into a library that uses the Event Asynchronous Pattern (EAP). There's a particular piece of functionality we care about:
  1. Before refreshing the list box, we save off a copy of the currently selected item.
  2. After refreshing the list box, we try to set the selected item based on our saved value.
At the top of the method, we save off the selected item:


And then inside our lambda expression, we try to set the selected item in the list box:

Set Selected Item in List Box
The object that we have here (the "Person" class) does not have a primary key, so we compare the first name and last name properties -- this definitely isn't ideal, but it works for our small data set.

With this code in place, the selection will be saved between refreshes. So, if we run the application and select an item (Isaac Gampu), our screen looks like this:

Initial Selection - Isaac Gampu
(Notice the selection in the top left corner). Then when we change the sorting and click the "Refresh" button, we see that Isaac Gampu is still selected:

Isaac Gampu still selected after refresh
For more details on how the lambda expressions and LINQ methods work, be sure to check out the associated resources: Learn to Love Lambdas (and LINQ, Too!).

And this brings us to the question:
Why can't we just set the selected item directly based on our saved person?
The proposal is to replace the code above ("Set selected item in list box") with the following:


This makes our method much simpler:


This looks great (and sounds a lot easier). But unfortunately, it doesn't work. Here's what happens. First, we make an initial selection (John Sheridan):

Initial Selection - John Sheridan
Then when we click "Refresh", we lose our selection:

No selection after Refresh
Why does this happen? For this we'll need to take a closer look at the difference between reference types and value types.

Reference Types, Value Types, and Equality
The difference between reference types and value types is how they are stored in memory. There are 2 memory locations we need to worry about: the stack and the heap.

I won't go into a full explanation of the stack and heap. You can get a good overview here: C# Heap(ing) and Stack(ing) in C#.

What's important to understand here is how equality is handled differently with reference types and value types.

Value Type Equality
Since value types are stored on the stack, equality is determined by comparing the values. This makes it easy to compare ints, bools, and chars. A struct is also a value type. Since a struct generally has multiple sub-values, equality is determined by comparing the values of each field and/or property.

Reference Type Equality
Since reference types are stored on the heap, equality is determined by looking at the pointer. If 2 objects point to the same object in memory, then they are considered to be equal. This means that they are only equal if they point to the same instance in memory.

But if we have 2 separate instances, then they will not be equal (at least with the default implementation; we'll look at another solution in just a bit).

Classes are reference types, so we end up running into this behavior quite a bit. Our "Person" is a class:


Observed Behavior
So why do we have a problem with our proposed code?


When we assign a value to the "SelectedItem" property of our list box, it looks through the items in the list to try to find one that is equal.

When we save off our "selectedPerson" object, we have an instance of the Person class (that holds "John Sheridan" in our example). When we reload our list box, we have a new collection of Person objects. One of those items has a value of "John Sheridan", but this is a different instance from the one that we saved off.

Because we have 2 different instances (the saved one and the one in the list), these are not considered to be equal. And that's why we get the observed behavior (no selection) instead of the expected behavior.

Now let's look at two solutions that will get our proposed code to work.

Option 1: Change Person to a Value Type
One option is to change the "Person" object from a reference type to a value type. In our case, this would involve changing it from a "class" to a "struct". The "Person" declaration is close to the same:


But because we just changed this to a value type, some of our other code breaks. Here's the updated code where we save off a copy of the selected item:


Since our "Person" is now a non-nullable value type, we need to treat it a little differently. The "as" operator only works with reference types since it can result in a null. So instead, we initialize "selectedPerson" to an empty "Person" object, then we make sure that the list box actually has a selected item. If it does, then we cast it to a "Person" and assign it to our variable.

The rest of the code stays the same. Here's our updated method:


And our behavior is as expected. If we run our application and select an item (Dave Lister):

Initial Selection - Dave Lister
And the click "Refresh", we see that our selected item is set appropriately:

Dave Lister still selected after Refresh
Because we're dealing with value types, the comparison is done by looking at the values of the properties: first name, last name, start date, and rating. If these values all match, then the items are considered by be equal.

So we've seen how we can change our data object to a value type, and our proposed code works as expected. But what if we want to keep our "Person" as a class? There's an option for that, too.

Option 2: Override Equals()
Our second option is to keep "Person" as a class (a reference type). The default behavior of "Equals" is what we saw above -- it only returns true if we're comparing the same instance. But we can override the default behavior with something that is more appropriate to our situation. Here's the code for that:


Notice that we have a "class" here. Then we override the "Equals()" method. First we cast our parameter to a "Person". When we use the "as" operator, we will get a null if the cast fails. Next we check for a "null". This could be because another object type was passed in or a null parameter was passed in. If either of these is true, then we return false (meaning, not equal).

Finally, we set up our own equality comparison based on the key properties: first name, last name, and start date. (I didn't include the rating since that could be changeable.)

Then we can go back to our original proposed method:


If we run this code, we see that it works as expected. We can select an item (John Crichton):

Initial Selection - John Crichton

And then after "Refresh", the item is still selected:

John Crichton still selected after Refresh
It would be nice if we could stop here, but things aren't quite so simple. If you notice in our "Person" class, we have a green squiggly. This tells us that there's a warning. We can see this in our build results:


This tells us that whenever we override "Equals()", we should also override "GetHashCode()". The hash code is used when we use this class as a key in a Dictionary. There are rules about creating hash codes that become important depending on how we're using the object. You can get more information on this here: MSDN Object.GetHashCode() Method.

Another thing that we should do when we override "Equals()" is to provide a generic version for our specific type: "Equals<Person>(Person obj)". But we won't do that today either.

As we can see, once we start going down the path of changing how equality works with an object, we have quite a bit of work to do.

Original Code
One of the questions that I received on the original code:
Why didn't you just override the Equals method?
There are a couple of reasons for this. The first reason is that we lose the lambda expressions and LINQ methods that I wanted to demonstrate here .

But the bigger reason is that we don't always have the option of changing our data objects. Even when we're constrained by our data, we can use LINQ to query it, filter it, sort it, and even easily locate items in a list.

Wrap Up
We don't usually have to worry about the difference between reference types and value types. But as we've seen, there is a big difference between them when we start to talk about equality comparisons. As usual, there are several different ways that we can approach the problem. And that's good. When we have options, we are free to select whichever one works best for our particular situation.

Happy Coding!

Sunday, July 19, 2015

Getting a Bit LINQ-ier

Last time we converted a file load method to be a bit more LINQ-y. The result was a compact and very readable method:


But should we be happy with this? Commenter "TomThumb" is not:
"Have you thought of using File.ReadLines() instead? It returns a lazily evaluated enumerable. It's arguably a bit more LINQy, and perhaps fits your use case a bit better (selecting subsets of the file)?"
Yep, this is probably a good idea. Let's take a closer look and do some informal metrics.

ReadAllLines vs. ReadLines
We'll start by looking at the difference between the methods ReadAllLines() and ReadLines(). Here are the method signatures from the documentation:



This shows us that "ReadAllLines" returns a string array, and "ReadLines" returns an string enumeration.

What's the difference? Well, "ReadAllLines" will read the entire file. "ReadLines" will read one line at a time as we enumerate through the file. If we stop enumerating, then the "ReadLines" will stop reading from the file. So this gives us an opportunity to short-circuit the file read.

And this is important because of how we're using the data from the file:


Pay attention to the "Take" method. Our file has about 40,000 records in it. But we may only "Take" 1,000 records, so there's no need for us to read the rest of the file.

This sounds good in theory, but let's put it into practice and see if we get a performance difference.

Comparing Performance
For this, we'll compare our original method (using "ReadAllLines") with a new method that uses "ReadLines". Here's the updated method:


And I'm curious about differences in the performance based on how much of the file that we read. So we'll do tests reading 1,000 records, 10,000 records, and the entire file (about 40,000 records).

1,000 Records
The application itself already has a duration timer built in, so we'll just use this. Now this shows the duration for the entire process which includes reading the file, processing the data into bitmaps, and loading them into a WPF list box.

The file load process is the fastest part of this process, so I expect to see the biggest differences when I only load a small portion of the data file.

Here are the results when we limit things to 1,000 records:

ReadAllLines - 1,000 Records
ReadLines - 1,000 Records

As expected, this is a pretty dramatic difference. Over several runs, the average with "ReadAllLines" was 1.316 seconds. The average with "ReadLines" was 0.951 seconds.

This makes sense since we don't have to read 39,000 records from the file, just the 1,000 that we're using. But let's keep going. I'm curious as to whether we'll keep that advantage with more records.

10,000 Records
The next tests were with 10,000 records. And the difference is still noticeable:

ReadAllLines - 10,000 Records
ReadLines - 10,000 Records

The average with "ReadAllLines" with 10,000 records was 9.311 seconds. The average with "ReadLines" was 9.042 seconds. Again, the bulk of the work being done here is creating bitmaps and loading the list box. But we see that there is about a 1/4 second difference in our results.

40,000 Records
For the last set of tests, I read the entire file which is about 40,000 records. This is where I was most curious. I wondered if the overhead of having the enumeration would out-weigh the efficiency of reading all the data into memory.

Let's look at the results:

ReadAllLines - 40,000 Records
ReadLines - 40,000 Records

This is where the tables turn -- but just a little bit. The average with "ReadAllLines" when we read the entire file is 37.811 seconds. The average with "ReadLines" is 37.877 seconds.

These results are so close (within a few 1/100ths of a second) that I don't feel right calling one "faster" than the other.

What this tells us is that when we "short-circuit" the file reading process (by only reading a portion of the file), we do get a definite advantage from "ReadLines". And when we read the entire file, we do not get a noticeable performance hit from using "ReadLines".

So, in this particular instance, it would be better for us to use "ReadLines".

Considerations
I have updated the code in the GitHub project: jeremybytes/digit-display. If you want to play with this code yourself, the file load method is in the FileLoader.cs file, and the read threshold is set in the MainWindow.xaml.cs file.

Here's our file loader method:


Now that we've made this method more LINQ-y by using a Read method that returns an IEnumerable instead of an array, we can look at taking this further.

I'm a big fan of enumerations and IEnumerable. There are some really cool things that we can do (particularly around lazy-loading). In this method, when we call "ToArray" it causes the enumeration to be evaluated. So any lazy-loading goes away right there. We force all of the records to be enumerated.

But we have another option. What if we were to push the enumeration further down in our application? So instead of returning a "string[]" from our "LoadDataStrings" method, we could return "IEnumerable<string>".

How would that affect our downstream code? Well here's where this method is used (in our MainWindow.xaml.cs file):


Notice that "rawData" is a string array, but this could just as easily be an "IEnumerable<string>". This would change how our code runs. This may be good or bad depending on our needs.

If we switch to an enumeration (rather than an array), then our "foreach" will end up going all the way back to our original enumeration from "ReadLines". This means that a line will be read from the file, then processed into a bitmap, then loaded into the list box before the next line is read from the file.

Is this a good thing? I'm not quite sure -- I'll need to think about this some more. One downside to doing things this way is that the file stays open during the entire process -- even while we're loading our UI controls.

With our current code (which calls "ToArray"), we're done with the file as soon as the file load method is finished. So the file can be closed before we start doing any processing on the data.

I'll leave things the way they are (with the arrays) for now. If you have a preference one way or the other, be sure to leave a comment.

Wrap Up
Thanks to "TomThumb" for making me think about things a bit more. Mathias actually does have a sidebar in his book that talks about the difference between "ReadAllLines" and "ReadLines". I appreciate the push to explore this a bit further.

When the question "How LINQ-y can you get?" comes up, the answer is often "a bit LINQ-ier". I'll look forward to exploring this (and a bunch of F#) as I dive deeper.

Happy Coding!

Thursday, July 16, 2015

Getting More LINQ-y

As I explore functional programming more, I'm learning how I haven't been using LINQ as much as I could be.

Last time, I talked about how I was excited about what I saw in Mathias Brandewinder's book Machine Learning Projects for .NET Developers (Amazon link). I made it through the first chapter, and I'm absorbing lots of stuff about machine learning and F#, but I also came across something simple that I hadn't thought about before:
LINQ can be used much more extensively than I've been using it.
Now, I've been a huge proponent of LINQ, but I usually think about it for things like handling existing data sets. But I don't really think about it as a way to create those data sets.

Functionalizing Code
I'll show what I'm talking about by going back to an article from last year where I needed to load data from a text file (Coding Practice: Displaying Bitmaps from Pixel Data).

Here's my original load from file method:


This is fairly straight-forward (and a bit verbose) code. It gets the data file name from configuration, then reads the file, and returns an array of strings (one for each line in the file).

There are a couple of quirks. Notice the "ReadLine()" with the comment "skip the first line". The first line contains header information, so I just did a read to ignore that.

The other quirk is that I have a parameter for the number of lines that I want to read. If the parameter is supplied, then I only want to read that number of lines (the original data file has 40,000 lines, and it was much easier to deal with smaller data sets). And if the parameter is not supplied, then we read in all the lines.

If you want to look at this code, it's available on GitHub: jeremybytes/digit-display. Look at the initial revision of the file here: FileLoader.cs original.

LINQ to the Rescue!
Now, Mathias shows code to load data from the same file/format (we'll look at that in just a bit). But instead of using a stream reader like I did, he used LINQ pretty much straight across.

So I went back and retro-fitted my file loading method. Here's what's left:


This code does the same thing as the method above. Well, not exactly the same, but close enough for government work.

Rather than using a stream reader, we use "ReadAllLines" to bring in the entire file. (I'll talk about the performance implications of this in just a bit). After that, we just use the standard LINQ methods to get the data we want.

The "Skip(1)" call will skip the header row. The "Take" method will limit the number of records to what's passed in to the parameter. As a side note, notice that I changed the parameter default from "0" to "int.MaxValue". This way if the parameter is omitted, the entire file will be read (well up to the max integer value anyway -- this would be a problem for large data sets (but then so would the rest of this application)).

Then we just use the "ToArray" method to get it into the final format that we want.

I don't know why I never thought of doing things this way before. Now there is a performance difference here. Since "ReadAllLines" reads the entire file, we're bringing in more data than we need, but the heavy-lifting of this application is done after this step, so the performance difference is negligible. But these are the things we need to think about as we make changes to our code.

[Update: 07/20/2015: As suggested in the comments, I explore the difference between "ReadAllLines" and "ReadLines" in Getting a Bit LINQ-ier.]

If you want to look at this code yourself, the latest version of this file is on GitHub: jeremybytes/digit-display. Here's a link to the file: FileLoader.cs current.

The Inspiration
Like I said, the way that Mathias loads the data in his book was the eye-opener. Here's that code (from Chapter 1):


This is doing multiple steps. The second method (ReadObservations) reads the data from the file. In addition to skipping the first line, it does a data transformation using the "Select" method.

And we can see this in the first method. It takes the string data (which is a collection of comma-separated integers) and turns it into an integer array. This process skips the first value because this tells what digit the data represents. Everything after than on the line is the pixel data.

More LINQ-y Goodness
So, I wasn't content with just the file loading part of the application. I also needed to take the string data and convert it into a list of integer values.

Here's my original attempt at that (just part of this particular method):


This isn't bad code. I split the line on the commas, then "foreach" over the elements to convert them from strings to integers. File here: DigitBitmap.cs original.

And here's the updated code:


Here's a link to the file on GitHub: DigitBitmap.cs current.

As far as lines of code is concerned, these are about equivalent. You might notice that the original code doesn't have the "Skip 1" functionality. That's because I took care of it later in the method (which resulted in an off-by-one error that you can read about in the original article).

A Bit of a Stumbling Block
The thing that I hadn't really thought about before was using "Select" to transform the data from string to integer. And this was a bit of a stumbling block for me.

I have seen "Select" mis-used in the past. The code sample that I saw called a method in "Select" that had side effects -- it mutated state on another object rather than simply returning data. This smelled really bad to me when I saw it. Since then, I've been careful and shied away from using "Select" with other methods.

But in this case, it's perfectly appropriate. We are not mutating data. We are not changing state. We are transforming the data -- and this is exactly what "Select" is designed for. This was a real eye-opener, and I'm going to be a bit more creative about how I use LINQ in the future.

Wrap Up
I've been a big fan of LINQ for a really long time. And I really like showing people how to use it (and if you don't believe me, just check out this video series: Lambdas and LINQ in C#). I'm really happy that I can still extend my outlook and find new and exciting things to do with my existing tools.

And I find myself getting sucked more into the functional world. The problems are interesting, the techinques are intriguing, and the people I know are awesome.

I'm pretty sure that by the time I get through this book, I'll be looking for ways to use functional programming (and most likely F#) as a primary tool in my toolbox.

Happy Coding!

Saturday, April 25, 2015

New Video: Deciphering the LINQ Join Method

I really love using the fluent syntax with LINQ. This gives me full access to all of the very useful extension methods.

In Part 2 of the Lambdas & LINQ video series, we took some time to understand the parameters of the Where method and also OrderBy. After seeing this, folks sometimes ask me: "What about Join?"

And why do they ask this question? Because this is the method signature:


Yikes.

But when we break things down, it's nothing that we haven't seen before. And that's exactly what we do in my latest video: Deciphering the Join Method.



If you'd rather have a text version, check out this article: The LINQ Join Method: Deciphering the Parameters.

And find the other videos, links to code on GitHub, PDF walkthroughs, and other articles here: Learn to Love Lambdas (and LINQ, Too)

I'm looking to produce other videos based on my articles (so that different folks can learn in the way that works best for them). If you have a favorite topics that you'd like to see put into video, let me know.

Happy Coding!

Tuesday, April 14, 2015

New Video: Declarative Programming with LINQ

I just published Part 3 of my video series on Lambda Expressions & LINQ in C#. This time around, we look at the difference between imperative programming and declarative programming.

Imperative Programming is what we're used to: we tell the computer *how* to do something. This usually involves giving step-by-step instructions such as looping through data, using "if" statements to make comparisons, and then doing the pieces of work that are important to our task.

Declarative Programming is a bit different: we tell the computer *what* we want done. Then we leave it up to the computer (or library) to figure out the rest. It turns out that we can use LINQ methods to make our code more declarative. And in doing this, we make our code easier to read and understand.

So be sure to check out Declarative Programming with LINQ:



This completes the basics of lambda expressions and LINQ. All of the videos are collected in this playlist:

Playlist: Lambda Expressions & LINQ in C#
I have a couple of bonus episodes planned (to cover some more details on captured variables and the Join method). So be sure to stay tuned for future episodes.

Happy Coding!

Sunday, April 12, 2015

New Video: Demystifying LINQ Methods

I just published Part 2 of my video series on Lambda Expressions and LINQ. You may have heard about Part 1 (Lambda Expression Basics) on This Week on Channel 9 (big thanks to Channel 9 for the mention).

A big problem with LINQ is the apparent chaos of the method signatures:


When we see this for the first time, it seems extremely complex. But once we dive into the different pieces, we see that things aren't as complicated as they seem. And that's exactly what we do in this video: Demystifying LINQ Methods:


While exploring LINQ, we mention a couple of other topics that are covered in separate videos:
As a reminder, Part 1 covers the basics of lambda expressions. And in future videos, we'll look at how LINQ can help us make our code more readable through declarative programming. We'll also take a look at the Join method and the intricacies of using captured variables in "for" loops.

Get links to all of the videos, plus code samples, additional articles, and a PDF walkthrough here: Learn to Love Lambdas (and LINQ, Too!)

Happy Coding!

Monday, April 6, 2015

New Video: Lambda Expression Basics

I just started a new video series based on my presentation Learn to Love Lambdas (and LINQ, Too!). LINQ is one of my favorite tools in C#, and lambda expressions play a key role in using LINQ methods.

Lambdas & LINQ in C# - Part 1: Lambda Expression Basics
In part 1 of the series, we take a look at the syntax of lambda expressions and how to create anonymous delegates. In addition, we look at captured variables which allows us to scope our variables more appropriately.

Watch Part 1 on YouTube (or here):



Future episodes will take a look at how to read and understand the signatures of LINQ methods. This allows us to use LINQ effectively in our code.

Coming Soon!
Part 2: Demystifying LINQ Methods -- 04/12/2015: NOW AVAILABLE!
Part 3: Declarative Programming with LINQ -- 04/14/2015: NOW AVAILABLE!
Plus, bonus episodes that look at the Join method syntax and the dangers of using captured variables with "for" loops.

Lots of good information coming. If you can't wait for the information, be sure to check out the PDF walkthroughs and articles available here: Learn to Love Lambdas (and LINQ, Too!).

Happy Coding!

Wednesday, February 25, 2015

The LINQ Join Method: Deciphering the Parameters

In the last few articles, I've been answering questions that have come up during my presentations of lambda expressions and LINQ, including whether we should use the methods with or without a predicate and how the OfType method actually works. To continue, we'll take a look at the "Join" method.

I'm going to spend a bit of time with "Join" because it's come up twice in the last few weeks -- once in an email and once during my presentation at the Las Vegas Code Camp last weekend. When I do my presentations, I use the fluent syntax of LINQ (also known as the method syntax where we "dot" methods together). This leads to the following question:
How do you use "Join" using the fluent syntax?
The answer is that we just need to parse the parameters of the method. When we do this, we may find ourselves using 3 different lambda expressions as parameters. So lets take things step by step.

The completed code for this can be found in the "BONUSJoinSyntax" branch of the lambdas-and-linq repository on GitHub: BONUSJoinSyntax branch. The sample is in the "JoinSyntax" project.

[Update 4/24/2015: If you'd like to see a walkthough of this on video, check out Deciphering the Join Method]

The Sample Data
When we use "Join", we combine 2 separate but related pieces of data. For this, we'll use a collection of "Person" objects and a collection of "Order" objects. Let's take a look at the objects:

From People.cs
From Orders.cs

This shows our objects. Notice that the "Order" class has a "CustomerId" property. This matches up with the "Id" property of the "Person" class. So these are the properties we will use to join our data.

The data itself comes from the "People" and "Orders" classes. Notice that each of these has a single static method that returns an IEnumerable. This is just a hard-coded list of objects that we can use in our application.

Using "Join" With the Query Syntax
We'll start by looking at how we use "Join" with the query syntax -- it's a bit easier to understand. This code is in the "OrderReports.cs" file. The idea is that we have some methods to generate reports based on our data. Then we have a console application where we display the data.

Here's a simple LINQ query that joins data from our People and Orders:


Notice that this method returns an "IEnumerable<dynamic>". We'll come back to why we're using this in a bit. Before we get to that, let's look at the body of the method.

First we call "GetPeople" and "GetOrders" to get some data to work with.

Next we create a LINQ query using the query syntax. "from p in people" says that we want to get data from the "people" collection and give it the alias "p". Then we have the join: "join o in orders" says that we want to add data from the "orders" collection, and we'll give it an alias of "o". Then we have the "on" statement. This specifies how the data is related. In this case, we say that the "Id" property of a "Person" is the same as the "CustomerId" property of an "Order". (And this is exactly what we noted above).

Finally, we have a "select" statement. For this we are using an anonymous type, which is why we have the "new" keyword without a specific type name. Inside the curly braces, we specify that we want our anonymous type to include the "LastName", "FirstName", and "OrderDate" properties.

The "var" keyword was created just for this purpose: so that we could have types without names. This is still strongly-typed, but the type only has an internal name. We can see this by putting our mouse over the "var" next to "orderDates".


This shows that "orderDates" is an "IEnumerable<T>". Right in the middle we see that "T is 'a". "'a" is the internal name that the compiler gives to our anonymous type. And at the very bottom, we can see the "'a" consists of 3 properties: LastName, FirstName, and OrderDate. (Also notice that the types for the properties are filled in as well.)

Back to the return type for the method: "IEnumerable<dynamic>". The reason I used "dynamic" is so that we can use the anonymous type in our output. Using "dynamic" is not ideal (as we'll see in just a bit), and I'd probably make this a named type in a reporting library -- but we won't worry about this today.

Running the Report
Now that we have a query, let's use it to output some data. For this, we have a simple console application in our project: "Program.cs".

Here's the code:


This calls the "OrderDatesByCustomer1" method that we just created. Then it iterates through each item and outputs it to the console.

If we put the mouse over the "var" with "item", we'll see that this is a "dynamic" object:


This means that we get absolutely zero IntelliSense on this. So inside the "foreach" loop, when we type "item." we don't get any help from Visual Studio. We have to type in "OrderDate", "FirstName", and "LastName" ourselves (and spelling and capitalization count). This is the reason why I would not use "dynamic" in a production reporting library -- it is non-discoverable, meaning we have to have intimate knowledge of the data that is coming back. (I'll update this code in a future article, but let's not let it distract us from looking at the LINQ queries.)

Here's the output when we run the console application:


We have about 20 records, and the first thing I notice is that they would benefit from being sorted. If you're curious about where this order came from, the records are in the order of the people first (which is the "outer" part of our join) and then in date order secondarily (which is the "inner" part of our join). And these are simply the order that the data comes out of the methods (not alphabetical or by date).

Let's do a few things to make this data easier to look at.

Adding Sorting and Filtering
Let's start by putting our results into order by date. That makes most sense based on the data we get back from this report. For this, we'll add an "orderby" statement to our query:


This brings some order to our results:


Next we'll add a date range filter. For this, we'll add a "where" statement:


Notice that we added "startDate" and "endDate" parameters to our method. We use these in the query with a new "where" statement to filter our data.

We need to modify our console application a bit to add the parameters. In this case, we're looking for items in the month of December 2014:


And here's the output:


Now we have a smaller set of records to work with. And this gives us a result set for us to try to match by using the fluent syntax.

Using "Join" With the Fluent Syntax
Let's try to do this same thing using the fluent LINQ syntax. In my presentation for "Learn to Love Lambdas (and LINQ, Too)", I show how to read the method signatures for several LINQ methods, including "Where", "OrderBy", and "SingleOrDefault". I won't repeat all of that here because you can see that in the downloadable materials (and in a video series that I'll be publishing in the new few weeks).

But things get a bit confusing when we look at the method signature for "Join":


This has a lot of parameters. But they are related. The first 2 parameters describe the data collections that we are joining, the next 2 parameters describe how those collections are related, and the last parameter lets us transform the data into our resulting records.

Let's step through them one at a time.

IEnumerable<TOuter> outer
This is one of our collections of data. In our case, this will be our collection of "Person" objects. So wherever we see the generic type "TOuter", we can replace it with "Person". In addition, since this is an extension method, this will actually be the type that we extend. (For more information on Extension Methods, see "Quick Byte: Extension Methods".)

Note: I'm using the word "collection" in the general sense. These are technically enumerations which can also represent calculated sequences.

IEnumerable<TInner> inner
This is the other collection that we are joining to. In our case, this will be our collection of "Order" objects. So wherever we see the generic type "TInner", we can replace it with "Order".

Key Selectors
Next, we have the key selectors. These are one of the confusing parts. But this just gives us a way to specify which properties are related. So for our "Person" (remember, this is "TOuter"), we want to use the "Id" property, and for our "Order" (the "TInner"), we want to use the "CustomerId" property.

Func<TOuter, TKey> outerKeySelector
The syntax for this is a bit strange: "Func<Person, TKey>". From working with Func, we know that this is a method that should take a "Person" as a parameter and return a "TKey". What does this mean? It means that we just need to provide a property that we can use in "equals" comparisons.

Note: If you aren't familiar with Func<T>, then you can take a look at "Get Func<>-y: Delegates in .NET".

In technical terms, this means that we need something that implements the "IEquatable" interface. If we're using standard .NET types (such as int, string, date, etc.), we don't have to do anything special; this is all built in. But if we're using a custom type, then we may need to include the interface or provide a separate equality provider. But this is usually beyond what we need to do.

Since our "Person" class is keyed off of the "Id" property (which is an integer), the actual method signature will be "Func<Person, int>" -- a method that takes a "Person" as a parameter and returns an "integer". We'll see this in a bit.

Func<TInner, TKey> innerKeySelector
To associate our "Order" class with our "Person" class, we use the "CustomerId" property (an integer) of the Order. This means that our actual method signature for this is "Func<Order, int>" -- a method that takes an "Order" as a parameter and returns an "integer".

One thing to notice is that the generic type parameter for both of our key selectors is "TKey". This means that we must use the same type (in our case, it is an integer). This makes sense since we need to compare these based on equality. If they are different types, they they couldn't be equal.

Func<TOuter, TInner, TResult> resultSelector
This last parameter is also a bit confusing. The purpose of this is to specify what we want our output to look like. Just like with our "select" statement in the LINQ query, we need to specify what we want our output to look like. And we'll use an anonymous type for our output just like we did above.

If we fill in our generic types, this means that the method signature will be "Func<Person, Order, 'a>" -- a method that takes a "Person" and an "Order" as parameters and returns an anonymous type.

Putting This All Together
Here's our initial LINQ statement using the fluent syntax:


Let's go through these parameters one at a time.

people
The first parameter is the "people" object. This is the "IEnumerable<Person>" (a.k.a. "IEnumerable<TOuter>"). Since "Join" is an extension method, our first parameter has been moved to the front.

orders
The next parameter (first inside the parentheses) is the "orders" object. This is the "IEnumerable<Orders>" (a.k.a. "IEnumerable<TInner>").

p => p.Id
Next we have our first lambda expression. Remember, this is a "Func<Person, int>" in our case. So we have a lambda expression that takes a "Person" as a parameter (our "p") and returns an integer (the "Id" property).

With lambda expressions, we can name our parameters whatever we like; however, it is very common to use single character parameter names to keep lambdas short. I use "p" to remind me that this is a "Person" object.

This syntax is very similar to what we see when we use the "OrderBy" method to specify a property for sorting. (See "Learn to Love Lambdas" for details on this.)

o => o.CustomerId
Our next lambda expression is similar to the first lambda. This one is a "Func<Order, int>". So we have a lambda expression that takes an "Order" as a parameter (our "o") and returns an integer (the "CustomerId" property).

By returning these two properties ("Id" and "CustomerId"), we let our "Join" method know how to match up the records in the different collections.

(p, o) => new { p.LastName, p.FirstName, o.OrderDate }
Our last lambda expression is what we want our resulting data to look like. As noted above, this needs to match the signature "Func<Person, Order, 'a>" in this case. So we have 2 parameters: Person and Order, and I've named these "p" and "o" respectively.

The body of the lambda is the type that we want to return. And just like when we used the "select" statement above, we use the "new" keyword to generate an anonymous type. And this type specifies that we get the "LastName" and "FirstName" properties from the "Person", and the "OrderDate" property from the "Order".

A Lot of Pieces
So, it seems that we have a lot of pieces, but if we compare this to the query syntax, we see that we have the same information, just in a bit of a different format.

Query Syntax

Fluent Syntax

Once you get comfortable with lambda expressions, the fluent syntax becomes very readable. This is one reason why teach people about lambda expressions and encourage them to use them so that they become familiar.

Using the Method
Next we'll update our console application to use the new method:


This is much the same as we have with the other method. And our output is the same as our initial output:


Let's fix this up a bit like we did with our query syntax example.

Adding Sorting and Filtering
We'll add sorting to get things into date order. One nice thing about using the fluent syntax is that we simply "dot" our methods together.

So to add sorting, we just add an "OrderBy" method call:


The "OrderBy" method needs to return a property that we can sort on. In this case, we use the "OrderDate" property. Notice that the syntax for this lambda expression is similar to what we saw with the key selectors.

This makes sense when we look at the signature for "OrderBy":


This has a "keySelector" parameter which is a "Func<TSource, TKey>" -- just like the key selectors in the "Join" parameters. The difference is that this key does a comparison (testing whether something is "greater", "lesser", or "equal") instead of an equality comparison like we have with "Join".

As a side note, I used the parameter name "r" to stand for "result" -- this is the anonymous type that is returned from the "Join" method.

When we add the "OrderBy", our results are sorted:


Finally, we'll add a filter. For this, we'll use the "Where" method. This takes a predicate like we saw when we were looking at various LINQ methods and predicates earlier.

So we'll add some parameters to our method and use them in our "Where":


The predicate for "Where" is a "Func<TSource, bool>", meaning that we take a particular type as a parameter and return a true/false value. In our case, the "TSource" is the anonymous type that is returned from our "Join".

Again, I use "r" here to stand for "result" (which is our anonymous type), and the lambda expression body returns true or false depending on whether the "OrderDate" property falls within the specified date range.

The Fluent Syntax
Once we get several of these methods together, we start to see the fluent syntax. Our call ends up as "Join(...).Where(...).OrderBy(...)".

We end up "piping" the results from one method to another. "Join" returns an IEnumerable<T>, which we use as the input for "Where". "Where" returns an IEnumerable<T>, which we use as the input for "OrderBy". And "OrderBy" returns an IOrderedEnumerable<T> which we use as our result.

As we need more functionality (such as grouping or aggregation), we simply "dot" more methods together in the order that we need.

Updated Console Application
If we update our console application to pass in the date parameters, we can run our new method. The final console application runs both of our methods: the query syntax and the fluent syntax. This lets us see the results side-by-side (sort of):


And we can see that our results are the same.

As a reminder, the code is available on GitHub: BONUSJoinSyntax branch of jeremybytes/lambdas-and-linq.

Query Syntax or Fluent Syntax?
So the question you probably have is whether you should use the query syntax or the fluent syntax. The answer is that it is entirely up to you. As mentioned previously, it's most important that you are consistent.

My personal preference has been to use the fluent syntax. This is primarily because there are many, many LINQ methods to choose from that are not available in the query syntax. This means that we need to mix query syntax with fluent syntax to get full advantage of LINQ. Because of this, I have a tendency to use the fluent syntax. This lets me stay in the mindset of "Func" and lambda expressions. And since I really love lambdas, this isn't very hard for me.

Wrap Up
The good news is that "Join" is one of the more complex LINQ methods out there. That means if you can understand how to parse the parameters for "Join", you're probably all set to parse the parameters for all of the other LINQ methods as well.

"Join" does have a lot of parameters. But as we've seen, if we take things one step at a time (and don't get frightened off), it's not very hard to implement. Although there are 5 parameters, the first 2 are the collections that we are joining, the next 2 are lambda expressions to tell how the collections are related, and the last parameter is the data transformation to the output that we want.

With this under our belt, we're well on our way to using LINQ methods effectively in our code.

Happy Coding!