Hi, this is Khawaja Asim and this module is the story of LINQ and C#.
LINQ Stands for
Language Intergraded Query. And in this blog post, we'll explore the features added to the C# language to facilitate LINQ.
Features of LINQ
Features like Lambda expressions and Extension methods, as well as how to write Quires in C#.
LINQ is a technology that gives you the ability to query data from the C# language. And by data, I mean you can query objects that are In-Memory on the heap, objects you've persisted into a database, objects behind web services, objects in XML, objects anywhere there's a LINQ provider.
And every application needs to query data, even if the query is only sorting some existing objects you already have on hand. To do this LINQ provides over 50 Query Operators that you can use. These Operators handle everything from Sorting, Joining, Grouping, Partitioning, Projecting, and of course, Filtering, so you can filter and find just the data that you want.
For instance, if you have a collection of employees, you might want to find just the employees who are Engineers.
So the first hurdle to overcome when building Query Features into a statically typed language like C#, where every object has a definite type, is what we'll provide these Query Features?
the LINQ Operators are defined as methods. And we know that methods have to be associated with a type. So if we want a method named, Where, which will act like a SQL WHERE Clause to filter data, take an input sequence and return some sort of subset of that, that is the output sequence, then on what type will this method appear? Now since LINQ is supposed to support a variety of data sources, everything from In-Memory data to data that is inside of a database.
Imagine if we defined a new type, an interface type called ISequence. Where ISequence can hide where the data is coming from. If it comes from a database then someone will have to write an SQLSequence that implements that interface and knows how to talk to the database, knows how to take that Where method invocation, and turn into a WHERE Clause inside of SQL Server.
The drawback here is that to implement this properly then ISequence will need to define a method for every Query Operator that we want. And of course, any class that implements that interface, anyone who wants to write a LINQ Provider, they would also have to implement all the methods defined by ISequence.
And the big problem here is that if Microsoft wants to introduce new Operators over time, as they have done, then that's going to break any existing clients that have implemented that interface.
We've learned in this class that when you implement an interface you have to provide all the members of that interface in your class definition. If not, it is a compiler error.
So when someone adds a new method, or a new field, or a new property to an interface, you have to change your code and recompile to get things working. So adding a method can break an existing client. And this makes this interface approach a little bit tricky. And ultimately Microsoft decided not to define a new type to hold all of these LINQ Operators.
That approach is just not flexible enough, it's not scalable enough, it doesn't support change over time. Instead, Microsoft took a different approach and added a new feature to the C# language. When selecting a type to use as the lowest level data source for LINQ, Microsoft selected an existing type from the framework class library. They type IEnumerable.
IEnumerable is the perfect interface for hiding the true source of data because it defines only one method.
GetEnumerator returns an object that will let you step through data one at a time like you would do in a foreach loop. So I can take this IEnumerable and write a foreach loop to go through each city name. And perhaps write it out to the Console. And although we're working on data that is In-Memory, it's an array of string, it doesn't have to be. We can hide all sorts of things behind an interface. It could actually be going out to a database and pulling a record back and turning it into an object and doing that each time we come through the foreach loop. So IEnumerable is perfect for hiding the source of data, but it doesn't do so well defining interesting methods for querying data.
You can only loop through the data source. But instead of defining new methods on this IEnumerable, Microsoft took the approach of adding extension methods to the language and extending IEnumerable. An extension method is a method that looks like it's a member of a given type when in reality it's just a static method on a different type.
DateTime is defined as a struct and structs are implicitly sealed, meaning it is illegal to create a new class that tries to derive from DateTime. You cannot inherit from a sealed class. Inheritance then is not an option for adding methods to DateTime. Which is unfortunate, because sometimes I want to add some additional methods that perform calculations on a DateTime and reuse that code throughout the rest of an application.
For example, given a date like (2002, 8, 9), I want to find out how many days are left in the current month.
There is a way to do this using DateTime.DaysInMonth, but if I want to shorten up that code so that I don't see the calculation everywhere and actually give it a named method, then my only option is a static method on a static class. We'll call it DaysTillEndOfMonth. And it's invoked by using DateUtilities.DaysToEndOfMonth. A static method invocation makes this code a little hard to read because the type name DateUtilities gets in the way. If I make DaysTillEndOfMonth an extension method, however, I can make this method appear as if it's an instance method of DateTime. And the way to make an extension method is to add to this keyword in front of the first parameter of a static method on a static class. Now anywhere that I have a DateTime, and this extension method is in scope.
which means the namespace where that extension method appears is either the same as the namespace on the end of it's including with the USING Clause. I can walk up to date and I can say, DaysToEndOfMonth. That's an extension method. You can see it has a slightly different icon here in the IDE.
The IDE is telling you it's an extension method, but it is invoked now like an instance method because I no longer have to pass the date in as the first parameter.
Extension methods are just a compiler trick. DaysToEndOfMonth is not really an instance method. And behind the scenes, the C# compiler will still generate code to call the static method on the static class and pass on that date as the first parameter, but the syntax is much easier to read.