现在的位置: 首页 > 综合 > 正文

LINQ Introduction Part 1 Of 3 By Sacha Barber(Refer from codeproject)

2013年10月06日 ⁄ 综合 ⁄ 共 27868字 ⁄ 字号 评论关闭
文章目录
 
   

 

Contents

Introduction

.NET 3.0 has now been released, so we should all know it by now shouldn't we? Jeez, it doesn't seem like that long ago that .NET 2.0 came along. Well for those that don't realize .NET 3.0 actually contains quite a lot of new stuff, such as:

  • Windows Workflow Foundation (WWF): Managing object lifecycles / persistent object storage
  • Windows Communication Foundation (WCF): The new communication layer
  • Windows Presentation Foundation (WPF): The new presentation layer (XAML)
  • Windows Cardspace: Which provides a standards-based solution for working with and managing diverse digital identities

So as you can see there is a lot to be learned right there. I'm in the process of learning WPF/WCF but I am also interested in a little gem called LINQ, that I believe will be part of .NET 3.5 and Visual Studio "Orcas" (as its known now). LINQ will add new features to both C# and VB.NET. LINQ has three flavours:

  • LINQ: Language Integrated Query for in memory objects (LINQ to Objects)
  • DINQ: Language Integrated Query for databases (LINQ to ADO NET)
  • XLINQ: Language Integrated Query for XML (LINQ to XML)

LINQ is pretty cool, and I have been looking into it as of late, so I thought I would write an article about what I have learned in the LINQ/DLINQ/XLINQ areas, in the hopes that it may just help some of you good folk. This article will be focussed on LINQ, and is the first in a series of 3 proposed articles.

The proposed article series content will be as follows:

  • Part1 (this article) : will be all about standard LINQ, which is used to query in memory data objects such as List, arrays etc etc
  • Part2 : will be about using DLINQ, which is LINQ for database data
  • Part3 : will be about using XLINQ, which is LINQ for XML data

But What Is LINQ Anyway?

Well standard LINQ is a new addition to .NET (it adds more dlls basically) that allows the programmer to query inline data as they probably would be used to doing with standard SQL-type syntax.

So where they may have had a query in a database or a SQL query string something like:

<span class="code-keyword">SELECT</span> * <span class="code-keyword">from</span> Books <span class="code-keyword">WHERE</span> QuatityInStock &gt; <span class="code-digit">50</span> <span class="code-keyword">AND</span> Price &gt; <span class="code-digit">50</span>.<span class="code-digit">00</span>

we would now write the following into as a valid LINQ query (assuming we have the relevant in memory data structure to support the query)

var RESULT =
  <span class="code-keyword">from</span> b Books
  <span class="code-keyword">where</span> b.QuatityInStock &gt; <span class="code-digit">50</span> <span class="code-keyword">AND</span> Price &gt; <span class="code-digit">50</span>.<span class="code-digit">00</span>
  <span class="code-keyword">select</span> b;

See how similar this is. It's very powerful. So thats basically what LINQ allows us to do. And as one can imagine, DLINQ does similar stuff but with database objects, and XLINQ does queries/creation over XML documents.

LINQ also introduces lot of concepts that have really come from other functional programming languages, such as Haskell, LISP. Some of these new concepts are:

  • Lambdas (which kind of allow anonymous functions (methods in .NET) to be called over a sequence, a nice source on this is here)
  • Recursive processing over a sequence
  • Lazy evaluation

These will hopefully become more familiar to you as we continue.

Prerequisites

To run the code supplied with this article you will need to install the May 2006 LINQ CTP which is available here, there is a new March 2007 CTP available, but its about 4GB for the full install (as its not just LINQ but the entire next generation of Visual Studio codenamed "Orcas") and quite fiddly, and probably going to change anyway, so the May 2006 LINQ CTP will be OK for the purpose of what this article is trying to demonstrate.

Other Interesting Readings

There are a number of interesting sources for LINQ and functional programming concepts. There is obviously the LINQ site and also some nice web examples, and also some other articles right here at Code Project. I'll list a few for those of you that are curious enough, and want more to look at:

What This Article Is Not

I've now told you where to download LINQ, and pointed you at some other LINQ resources and further readings (which I urge you to do) so by now you are probably thinking "what's left to discuss?" Well the honest answer is that this article's content could probably all be found quite easily using the other resources shown above. But you never know, this article just might put a new spin on things, and help you to understand LINQ in a different way, as each person has a different writing style, so too, does each person have a different learning style. Some folk just may like this article. And to be honest I quite enjoy writing articles, so I'll continue in the hope that someone will like this article's contents.

I do, however, want people to know (just so people know that I am not selling myself as a purveyor of new knowledge), that all the information in this article is neither novel or really original, it can all be found easily using the web or by trawling the LINQ documentation. But sometimes it's nice to let someone else go through the learning for you and to learn from what they learned. See it as my journey into learning LINQ, which I am sharing with you here.

Although to be honest it's not really standard LINQ that excites me it's DLINQ/XLINQ, for which there is not so much freely available information. So that really is a case of trawling the documentation. But fear not, that is what I will be doing for you good folk in the next two articles. So stay tuned for those future articles. It just would not have made sense to write about those two without some sort of words about standard LINQ.

Still Interested?

If (Yes==UserResponse) 
{
    SELECT RestOfArticleContent
}

A Little Word About The Attached demo Project

Before I delve into the nitty-gritty of LINQ, I would just like to mention a bit about the provided demo application. It looks like the figure shown below.

As you can see it comprises a left panel and a right area. On the left the user is able to view a PropertyGrid and a Numeric Up / Down control for each of the source Lists.

Where the user is able to use the Numeric Up / Down to examine the individual query source List data elements, where the PropertyGrid will always show the current list item as requested by the user. The query source List may not always be the same List, it will depend on the type of query being performed. However the PropertyGrid will always allow the user to examine the current query source List in the manner just described.

The main data query sources used for most queries will be simple based on List objects, which contain some really simple class objects. Let's have a look at an example data List objects

_itemList = <span class="code-keyword">new</span> List&lt;Item&gt; {
    { ItemID = <span class="code-digit">1</span>, ItemName = <span class="code-string">"</span><span class="code-string">Enclopedia"</span>, 
        Category=<span class="code-string">"</span><span class="code-string">Knowledge"</span>, UnitPrice = <span class="code-digit">55</span>.99M, UnitsInStock = <span class="code-digit">39</span> }, 
    { ItemID = <span class="code-digit">2</span>, ItemName = <span class="code-string">"</span><span class="code-string">Trainers"</span>, 
        Category=<span class="code-string">"</span><span class="code-string">Sports"</span>, UnitPrice = <span class="code-digit">75</span>.00M, UnitsInStock = <span class="code-digit">17</span> }, 
    { ItemID = <span class="code-digit">3</span>, ItemName = <span class="code-string">"</span><span class="code-string">Box of CDs"</span>,
        Category=<span class="code-string">"</span><span class="code-string">Storage"</span>, UnitPrice = <span class="code-digit">4</span>.99M, UnitsInStock = <span class="code-digit">13</span> }, 
    { ItemID = <span class="code-digit">4</span>, ItemName = <span class="code-string">"</span><span class="code-string">Tomatoe ketchup"</span>, 
        Category=<span class="code-string">"</span><span class="code-string">Food"</span>, UnitPrice = <span class="code-digit">0</span>.56M, UnitsInStock = <span class="code-digit">53</span> }, 
    { ItemID = <span class="code-digit">5</span>, ItemName = <span class="code-string">"</span><span class="code-string">IPod"</span>, 
        Category=<span class="code-string">"</span><span class="code-string">Entertainment"</span>, UnitPrice = <span class="code-digit">220</span>.99M, UnitsInStock 
        = <span class="code-digit">0</span> }, 
    { ItemID = <span class="code-digit">6</span>, ItemName = <span class="code-string">"</span><span class="code-string">Rammstein CD"</span>, 
        Category=<span class="code-string">"</span><span class="code-string">Entertainment"</span>, UnitPrice = <span class="code-digit">7</span>.99M, UnitsInStock = 
        <span class="code-digit">120</span> }, 
    { ItemID = <span class="code-digit">7</span>, ItemName = <span class="code-string">"</span><span class="code-string">War of the worlds DVD"</span>, 
        Category=<span class="code-string">"</span><span class="code-string">Entertainment"</span>, UnitPrice = <span class="code-digit">6</span>.99M, UnitsInStock = 
        <span class="code-digit">15</span> }, 
    { ItemID = <span class="code-digit">8</span>, ItemName = <span class="code-string">"</span><span class="code-string">Cranberry Sauce"</span>, 
        Category=<span class="code-string">"</span><span class="code-string">Food"</span>, UnitPrice = <span class="code-digit">0</span>.89M, UnitsInStock = <span class="code-digit">6</span> }, 
    { ItemID = <span class="code-digit">9</span>, ItemName = <span class="code-string">"</span><span class="code-string">Rice steamer"</span>, 
        Category=<span class="code-string">"</span><span class="code-string">Food"</span>, UnitPrice = <span class="code-digit">13</span>.00M, UnitsInStock = <span class="code-digit">29</span> }, 
    { ItemID = <span class="code-digit">10</span>, ItemName = <span class="code-string">"</span><span class="code-string">Bunch of grapes"</span>, 
        Category=<span class="code-string">"</span><span class="code-string">Food"</span>, UnitPrice = <span class="code-digit">1</span>.19M, UnitsInStock = <span class="code-digit">4</span> }};
 
    _orderList = <span class="code-keyword">new</span> List&lt;Order&gt; {
        { OrderID = <span class="code-digit">1</span>, OrderName = <span class="code-string">"</span><span class="code-string">John Smith"</span>, OrderDate = 
            DateTime.Now }, 
        { OrderID = <span class="code-digit">2</span>, OrderName = <span class="code-string">"</span><span class="code-string">Professor X"</span>, OrderDate = 
            DateTime.Now }, 
        { OrderID = <span class="code-digit">3</span>, OrderName = <span class="code-string">"</span><span class="code-string">Naomi Campbell"</span>, OrderDate = 
            DateTime.Now }, 
        { OrderID = <span class="code-digit">4</span>, OrderName = <span class="code-string">"</span><span class="code-string">The Hulk"</span>, OrderDate = 
            DateTime.Now }, 
        { OrderID = <span class="code-digit">5</span>, OrderName = <span class="code-string">"</span><span class="code-string">Malcolm X"</span>, OrderDate = 
            DateTime.Now  }};

So it can be seen that the 1st List simply contains 10 Item objects, and the 2nd List simply contains 10 Order objects. But what do these Item and Order objects look like? As I previously said, they are very simply objects, that are really dumb, and simply there to showcase the talents of what can be done with LINQ.

<span class="code-keyword">using</span> System;
<span class="code-keyword">using</span> System.Collections.Generic;
<span class="code-keyword">using</span> System.Text;
 
<span class="code-keyword">namespace</span> LinqApp
{
    <span class="code-keyword">public</span> <span class="code-keyword">class</span> Item
    {
        <span class="code-preprocessor">#region</span> Instance fields
        <span class="code-keyword">private</span> <span class="code-keyword">int</span> itemID; 
        <span class="code-keyword">private</span> <span class="code-keyword">string</span> itemName;
        <span class="code-keyword">private</span> <span class="code-keyword">string</span> category;
        <span class="code-keyword">private</span> <span class="code-keyword">decimal</span> unitPrice;
        <span class="code-keyword">private</span> <span class="code-keyword">int</span> unitsInStock;
        <span class="code-preprocessor">#endregion</span>
        <span class="code-preprocessor">#region</span> Ctor
        <span class="code-SummaryComment">///</span><span class="code-comment"> <span class="code-SummaryComment">&lt;</span><span class="code-SummaryComment">summary</span><span class="code-SummaryComment">&gt;</span>
</span>        <span class="code-SummaryComment">///</span><span class="code-comment"> ctor
</span>        <span class="code-SummaryComment">///</span><span class="code-comment"> <span class="code-SummaryComment">&lt;</span><span class="code-SummaryComment">/</span><span class="code-SummaryComment">summary</span><span class="code-SummaryComment">&gt;</span>
</span>        <span class="code-keyword">public</span> Item()
        {
 
        }
        <span class="code-preprocessor">#endregion</span>
        <span class="code-preprocessor">#region</span> Public Properties
        <span class="code-keyword">public</span> <span class="code-keyword">int</span> ItemID
        {
            <span class="code-keyword">get</span> { <span class="code-keyword">return</span> itemID;}
            <span class="code-keyword">set</span> { itemID = value; }
        }
 
        <span class="code-keyword">public</span> <span class="code-keyword">string</span> ItemName
        {
            <span class="code-keyword">get</span> { <span class="code-keyword">return</span> itemName;}
            <span class="code-keyword">set</span> { itemName = value; }
        }
 
        <span class="code-keyword">public</span> <span class="code-keyword">string</span> Category
        {
            <span class="code-keyword">get</span> { <span class="code-keyword">return</span> category;}
            <span class="code-keyword">set</span> { category = value; }
        }
 
        <span class="code-keyword">public</span> <span class="code-keyword">decimal</span> UnitPrice
        {
            <span class="code-keyword">get</span> { <span class="code-keyword">return</span> unitPrice;}
            <span class="code-keyword">set</span> { unitPrice = value; }
        }
 
        <span class="code-keyword">public</span> <span class="code-keyword">int</span> UnitsInStock
        {
            <span class="code-keyword">get</span> { <span class="code-keyword">return</span> unitsInStock;}
            <span class="code-keyword">set</span> { unitsInStock = value; }
        }
 
        <span class="code-keyword">public</span> <span class="code-keyword">string</span> ToString()
        {
            <span class="code-keyword">return</span>  <span class="code-string">"</span><span class="code-string">ItemID :"</span> + ItemID + <span class="code-string">"</span><span class="code-string">/r/n"</span> +
                    <span class="code-string">"</span><span class="code-string">ItemName :"</span> + ItemName + <span class="code-string">"</span><span class="code-string">/r/n"</span> +
                    <span class="code-string">"</span><span class="code-string">Category :"</span> + Category + <span class="code-string">"</span><span class="code-string">/r/n"</span> +
                    <span class="code-string">"</span><span class="code-string">UnitPrice :"</span> + UnitPrice + <span class="code-string">"</span><span class="code-string">/r/n"</span> +
                    <span class="code-string">"</span><span class="code-string">UnitsInStock :"</span> + UnitsInStock;
        }
        <span class="code-preprocessor">#endregion</span>
    }
}
 
 
<span class="code-keyword">using</span> System;
<span class="code-keyword">using</span> System.Collections.Generic;
<span class="code-keyword">using</span> System.Text;
 
<span class="code-keyword">namespace</span> LinqApp
{
    <span class="code-keyword">public</span> <span class="code-keyword">class</span> Order
    {
        <span class="code-preprocessor">#region</span> Instance fields
        <span class="code-keyword">private</span> <span class="code-keyword">int</span> orderID; 
        <span class="code-keyword">private</span> <span class="code-keyword">string</span> orderName; 
        <span class="code-keyword">private</span> DateTime orderDate;
        <span class="code-preprocessor">#endregion</span>
        <span class="code-preprocessor">#region</span> Ctor
        <span class="code-SummaryComment">///</span><span class="code-comment"> <span class="code-SummaryComment">&lt;</span><span class="code-SummaryComment">summary</span><span class="code-SummaryComment">&gt;</span>
</span>        <span class="code-SummaryComment">///</span><span class="code-comment"> ctor
</span>        <span class="code-SummaryComment">///</span><span class="code-comment"> <span class="code-SummaryComment">&lt;</span><span class="code-SummaryComment">/</span><span class="code-SummaryComment">summary</span><span class="code-SummaryComment">&gt;</span>
</span>        <span class="code-keyword">public</span> Order()
        {
 
        }
        <span class="code-preprocessor">#endregion</span>
        <span class="code-preprocessor">#region</span> Public Properties
        <span class="code-keyword">public</span> <span class="code-keyword">int</span> OrderID
        {
            <span class="code-keyword">get</span> { <span class="code-keyword">return</span> orderID;}
            <span class="code-keyword">set</span> { orderID = value; }
        }
        <span class="code-keyword">public</span> <span class="code-keyword">string</span> OrderName
        {
            <span class="code-keyword">get</span> { <span class="code-keyword">return</span> orderName;}
            <span class="code-keyword">set</span> { orderName = value; }
        }
        <span class="code-keyword">public</span> DateTime OrderDate
        {
            <span class="code-keyword">get</span> { <span class="code-keyword">return</span> orderDate;}
            <span class="code-keyword">set</span> { orderDate = value; }
        }
 
        <span class="code-keyword">public</span> <span class="code-keyword">string</span> ToString()
        {
            <span class="code-keyword">return</span>  <span class="code-string">"</span><span class="code-string">OrderID :"</span> + OrderID + <span class="code-string">"</span><span class="code-string">/r/n"</span> +
                    <span class="code-string">"</span><span class="code-string">OrderName :"</span> + OrderName + <span class="code-string">"</span><span class="code-string">/r/n"</span> +
                    <span class="code-string">"</span><span class="code-string">OrderDate :"</span> + OrderDate;
        }
        <span class="code-preprocessor">#endregion</span>
    }
}

The right hand area of the demo application shows the current query (actual LINQ syntax) and the results obtained.

This is pretty much how all the source data for the demo application is done, there may be some exceptions, where simple arrays of values are used instead of List objects, but I'll mention those when we come to them.

Think of the demo app as a mini LINQ playground.

So that's about all I think you'll need to know about the demo app, for the moment, so shall we continue?

OK Lets Crack On Then

As I previously stated standard LINQ (not DLINQ / XLINQ) operates on in memory data structures such as arrays, collections etc etc. LINQ actually does this using methods known as Standard Query Operators.

The new .NET 3.0 System.Query.Sequence static class declares a set of methods which exposes these Standard Query Operators.

The majority of the Standard Query Operators are extension methods that extend IEnumerable<T>.

I think the best way to tackle this subject is to introduce the LINQ Standard Query Operators. And give you a formal definition and an example of each one.

The LINQ specification details the following operators:

  • Restriction operators
  • Projection operators
  • Partitioning operators
  • Join operators
  • Concatenation operator
  • Ordering operators
  • Grouping operators
  • Set operators
  • Conversion operators
  • Equality operator
  • Element operators
  • Generation operators
  • Quantifiers
  • Aggregate operators

Where the Standard Query Operators operate on sequences. Any object that implements the interface IEnumerable<T> for some type T is considered a sequence of that type.

So you can see it's quite some beast. So what I'll attempt to do is give one formal definition and one example for each of the operators. I'll leave further reading (as I am showing one example, there are many possibilities for each operator) as an exercise for the reader.

Operator Instructions

Time for some examples.

Restriction (WHERE) Operator

The Restriction operator filters a sequence based on a predicate.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; Where&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, bool&gt; predicate);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; Where&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, <span class="code-keyword">int</span>, bool&gt; predicate);

Predicates

What's a predicate you say.

Well Wikipedia says:

"In formal semantics a predicate is an expression of the semantic type of sets. An equivalent formulation is that they are thought of as indicator functions of sets, i.e. functions from an entity to a truth value.

In predicate logic, a predicate can take the role as either a property or a relation between entities."

And the LINQ Standard Query Operators documentation says:

"The example below declares a local variable predicate of a delegate type that takes a Customer and returns bool. The local variable is assigned an anonymous method that returns true if the given customer is located in London. The delegate referenced by predicate is subsequently used to find all the customers in London."

Func&lt;Customer, bool&gt; predicate = c =&gt; c.City == <span class="code-string">"</span><span class="code-string">London"</span>;
IEnumerable&lt;Customer&gt; customersInLondon = customers.Where(predicate);

So let's consider this simple example. What we would end up with is an expression that would be something like:

IEnumerable&lt;Customer&gt; customersInLondon = customers.Where(c =&gt; c.City 
  == <span class="code-string">"</span><span class="code-string">London"</span>);

which could also be written in a more conventional way (that those more familiar with SQL would probably like)

IEnumerable&lt;Customer&gt; customersInLondon =
    from c <span class="code-keyword">in</span> customers
    where c.City == <span class="code-string">"</span><span class="code-string">London"</span>
    select c;

we could even be lazier than this, and instead of writing:

IEnumerable&lt;Customer&gt; customersInLondon = 
    from c <span class="code-keyword">in</span> customers
    where c.City == <span class="code-string">"</span><span class="code-string">London"</span>
    select c;

we could write:

var customersInLondon = 
    from c <span class="code-keyword">in</span> customers  
    where c.City == <span class="code-string">"</span><span class="code-string">London"</span>
    select c;

That's how LINQ uses predicates. Basically the easiest way of thinking about what predicates are is to think about them as filters, that will evaluate to True or False, and as such will filter the IEnumerable<T> data source that the Expression is being applied to only contain the elements that match the filter (predicate).

But we digress. We needed to do this once, so that Predicates could be explained. But now that you've all got the hang of that we'll revisit the 1st Standard Query Operator.

Restriction (WHERE) Operator Revisited

Recall the Restriction (Where) Query Operator was defined as:

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; Where&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, bool&gt; predicate);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; Where&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, <span class="code-keyword">int</span>, bool&gt; predicate);

The Restriction Query operator can be of either of the forms shown above, where the the first argument of the predicate function represents the element to test. The second argument, if present, represents the zero-based index of the element within the source sequence.

So let's see a real world example (using the attached demo project and the _itemList List local data source)

var iSmall =
    from it <span class="code-keyword">in</span> _itemList
    where it.UnitPrice &lt; <span class="code-digit">50</span>.00M
    select it;

A Little Word About "Var"

One thing that is of interest here, which is the use of the var within this example above. This looks reminiscent of days of old - VB, Flash, JavaScript - basically any not-strongly typed language. And those days were bad. These days we expect and use strongly typed objects. Even better these days we also have Generics, which bring us even more Type control over software we write. Yet here is LINQ code, which is after all new stuff, that will probably part of .NET 3.0. Is this good?

Consider this statement:

"It is also not required to declare type of query variable, because type inference automatically deduces the type when the var keyword is used."

Concepts behind the C# 3.0 language, Tomas Petricek.

What do we think of this? Well it's certainly better that what VB used to do, which was to determine the type at runtime. What LINQ does it to determine the type at compile time. So used wisely the var type can actually help developers and decrease coding time. Of course if you really want to be a stickler for hardcore typing then what one would have to do something like what is shown below:

EXAMPLE 1

IEnumerable&lt;Item&gt; iSmall =
    from it <span class="code-keyword">in</span> _itemList
    where it.UnitPrice &lt; <span class="code-digit">50</span>.00M
    select it;

Instead of:

EXAMPLE 2

var iSmall =
    from it <span class="code-keyword">in</span> _itemList
    where it.UnitPrice &lt; <span class="code-digit">50</span>.00M
    select it;

Can you see the difference?

In the 1st case, we were actually selecting the result type, and it which happens to be of Type Item, so we have to declare the result of the query as IEnumerable<Item> as this matches the query result. This is how to strongly type a query result. If, however, the query was changed to not return an Item Type, say, a string Type then we would need to change the query result type from IEnumerable<Item> to IEnumerable<string> we would have to remember to do this. Also if we had some complicated nested, joined, aggregate (SUM, COUNT) type operators as part of the query, it might be quite a complex type that we have to declare as a return type.

What would you guess the query result type be for this:

from c <span class="code-keyword">in</span> customers
    join o <span class="code-keyword">in</span> orders on c.CustomerID equals o.CustomerID into co
    from o <span class="code-keyword">in</span> co.DefaultIfEmpty(emptyOrder)
    select <span class="code-keyword">new</span> { c.Name, o.OrderDate, o.Total };

or how about this one:

from c <span class="code-keyword">in</span> customers
select <span class="code-keyword">new</span> 
{
    c.CompanyName, YearGroups =
        from o <span class="code-keyword">in</span> c.Orders
        group o by o.OrderDate.Year into yg
        select <span class="code-keyword">new</span> 
    {
        Year = yg.Key, MonthGroups =
            from o <span class="code-keyword">in</span> yg
            group o by o.OrderDate.Month into mg
            select <span class="code-keyword">new</span> 
        {
            Month = mg.Key, Orders = mg 
        }
    }
};

See, it gets tricky. We all know typing is good and is our friend. But sometimes it can also be fairly complicated as well.

In the 2nd example above, we simply use var instead of strongly typing the result of the query. This works, and the correct types are inferred, as they would be even for the most complicated query results. Also if we change the query, we don't have to change the var, as it will simply infer the new required types automatically. Job done.

It is personal preference, but var can save time and frustration. Just use it wisely and all should be cool.

Projection (SELECT) Operator

The Projection operator performs a projection over a sequence.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;S&gt; Select&lt;T, S&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,    
    Func&lt;T, S&gt; selector);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;S&gt; Select&lt;T, S&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,    
    Func&lt;T, <span class="code-keyword">int</span>, S&gt; selector);

The Projection Query operator can be of either of the forms shown above, where the first argument of the selector function represents the element to process. The second argument, if present, represents the zero based index of the element within the source sequence.

So lets see a real world example (using the attached demo project and the _itemList List local data source)

var iNames = from i <span class="code-keyword">in</span> _itemList select i.ItemName;

And maybe another example:

 var namesAndPrices =
     _itemList.Where(i =&gt; i.UnitPrice &gt;= <span class="code-digit">10</span>).Select(i =&gt; <span class="code-keyword">new</span> { i.ItemName,
    i.UnitPrice }).ToList();

This is an interesting statement. The 1st part is the predicate i => i.UnitPrice >= 10, so only those items with a UnitPrice > 10, are actually selected. Then of those that are selected, we generate a new list (using the ToList() method) which only include ItemName and UnitPrice. Neat huh?

There is also SelectMany, which I have not included here. But after you install LINQ, you can play with this yourself.

Partitioning (Take / Skip) Operator

The Partitioning operator is made up of four parts:

Take

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; Take&lt;T&gt;(<span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,<span class="code-keyword">int</span> count);

So let's see a real world example (using the attached demo project and the _itemList List local data source)

var MostExpensive2 = _itemList.OrderByDescending(i =&gt; i.UnitPrice).Take(<span class="code-digit">2</span>);

Where this example gets the two most expensive Items.

Skip

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; Skip&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,<span class="code-keyword">int</span> count);

So let's see a real world example (using the attached demo project and the _itemList List local data source)

var AllButMostExpensive2 = 
    _itemList.OrderByDescending(i =&gt; i.UnitPrice).Skip(<span class="code-digit">2</span>);

Where this example gets all but the two most expensive Items.

TakeWhile

The TakeWhile operator yields elements from a sequence while a test is true and then skips the remainder of the sequence. I will leave this as an exercise for the reader.

SkipWhile

The SkipWhile operator skips elements from a sequence while a test is true and then yields the remainder of the sequence. I will leave this as an exercise for the reader.

Join Operator

The Join operator is made up of two parts:

Join

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;V&gt; Join&lt;T, U, K, V&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; outer,
    IEnumerable&lt;U&gt; inner,
    Func&lt;T, K&gt; outerKeySelector,
    Func&lt;U, K&gt;&gt; innerKeySelector,
    Func&lt;T, U, V&gt; resultSelector);

It looks fairly nasty, but breaking it down a bit, it's really just saying get an outer data source, get an inner data source, get in outer key, get an inner key, and get the resultSet.

So let's see a real world example (using the attached demo project and the _itemList List and _orderList local data sources)

var itemOrders =
    from i <span class="code-keyword">in</span> _itemList
    join o <span class="code-keyword">in</span> _orderList on i.ItemID equals o.OrderID
    select <span class="code-keyword">new</span> { i.ItemName, o.OrderName };

Where this example gets all Order objects that have the same OrderID value as that of the current Item.ItemID.

JoinGroup

The GroupJoin operator performs a grouped join of two sequences based on matching keys extracted from the elements. I will leave this as an exercise for the reader.

Concatenation Operator

The Concat operator concatenates two sequences.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; Concat&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; first,
    IEnumerable&lt;T&gt; second);

So lets see a real world example (using the attached demo project and the _itemList List local data source)

var items = (   from itEnt <span class="code-keyword">in</span> _itemList
                where itEnt.Category.Equals(<span class="code-string">"</span><span class="code-string">Entertainment"</span>)
                select itEnt.ItemName
             ).Concat
             (
                from it2 <span class="code-keyword">in</span> _itemList
                where it2.Category.Equals(<span class="code-string">"</span><span class="code-string">Food"</span>)
                select it2.ItemName
             ).Distinct();

Where this example gets all Item objects which have a Category of "Entertainment" and Concatenates that with the result of all Item objects which have a Category of "Food" and ensures there are no duplicates, by using the Distinct() method.

Order (OrderBy / ThenBy) Operator

The OrderBy / ThenBy family of operators order a sequence according to one or more keys.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> OrderedSequence&lt;T&gt; OrderBy&lt;T, K&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> OrderedSequence&lt;T&gt; OrderBy&lt;T, K&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector, IComparer&lt;K&gt; comparer);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> OrderedSequence&lt;T&gt; OrderByDescending&lt;T, K&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> OrderedSequence&lt;T&gt; OrderByDescending&lt;T, K&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source, 
    Func&lt;T, K&gt; keySelector,
    IComparer&lt;K&gt; comparer);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> OrderedSequence&lt;T&gt; ThenBy&lt;T, K&gt;(
    <span class="code-keyword">this</span> OrderedSequence&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> OrderedSequence&lt;T&gt; ThenBy&lt;T, K&gt;(
    <span class="code-keyword">this</span> OrderedSequence&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector,
    IComparer&lt;K&gt; comparer);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> OrderedSequence&lt;T&gt; ThenByDescending&lt;T, K&gt;(
    <span class="code-keyword">this</span> OrderedSequence&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> OrderedSequence&lt;T&gt; ThenByDescending&lt;T, K&gt;(
    <span class="code-keyword">this</span> OrderedSequence&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector,
    IComparer&lt;K&gt; comparer);

So let's see a real world example (using the attached demo project and the _itemList List local data source)

var orderItems = 
    _itemList.OrderBy(i =&gt; i.Category).ThenByDescending(i =&gt; i.UnitPrice);

Where this example gets all Items objects and simply order them 1st by Category and then by UnitPrice.

Group (GroupBy) Operator

The GroupBy operator groups the elements of a sequence.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;IGrouping&lt;K, T&gt;&gt; GroupBy&lt;T, K&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;IGrouping&lt;K, T&gt;&gt; GroupBy&lt;T, K&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector,
    IEqualityComparer&lt;K&gt; comparer);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;IGrouping&lt;K, E&gt;&gt; GroupBy&lt;T, K, E&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector,
    Func&lt;T, E&gt; elementSelector);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;IGrouping&lt;K, E&gt;&gt; GroupBy&lt;T, K, E&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector,
    Func&lt;T, E&gt; elementSelector,
    IEqualityComparer&lt;K&gt; comparer);
 
<span class="code-keyword">public</span> <span class="code-keyword">interface</span> IGrouping&lt;K, T&gt; : IEnumerable&lt;T&gt;
 
{
    K Key { <span class="code-keyword">get</span>; }
}

So lets see a real world example (using the attached demo project and the _itemList List local data source)

var itemNamesByCategory =
    from i <span class="code-keyword">in</span> _itemList
    group i by i.Category into g
    select <span class="code-keyword">new</span> { Category = g.Key, Items = g };

NOTE: This example is quite different from those supplied with the LINQ CTP, and I could not get those to work, as I think the syntax may have changed since Microsoft wrote the LINQ documentation (for example GroupBy did not seem to liked, at least not how they described for this specfic query). The example above does actually work.

This example gets all Item objects and simply groups them by Category. Then it selects the results into a new List (on the fly) where the Category is the key of the group result from the previous step, and the Items is set to be the current value of the items that matched the current grouping in the previous step. A little confusing, but let's have a look at the results that may help a little.

Category : Knowledge
Enclopedia

Category : Sports
Trainers

Category : Storage
Box of CDs

Category : Food
Tomatoe ketchup
Cranberry Sauce
Rice steamer
Bunch of grapes

Category : Entertainment
IPod
Rammstein CD
War of the worlds DVD

It can be seen that we have all the Item objects from the initial List it's just that now they have been grouped. I grant you it's not as nice as standard SQL syntax, but it does the job.

Set (Distinct / Union / Intersect / Except) Operators

The Set operators is made up of four parts:

Distinct

The Distinct operator eliminates duplicate elements from a sequence.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; Distinct&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source);

So let's see a real world example (using the attached demo project and the _itemList List local data source)

var itemCategory = (from i <span class="code-keyword">in</span> _itemList select i.Category).Distinct()

Where this example gets the a unique list of all the Categories for the Items List

Union

The Union operator produces the set union of two sequences

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; Union&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; first,
    IEnumerable&lt;T&gt; second);

So let's see a real world example (using the attached demo project and the _itemList and _orderList List local data sources)

var un = (from i <span class="code-keyword">in</span> _itemList select i.ItemName).Distinct()
        .Union((from o <span class="code-keyword">in</span> _orderList select o.OrderName).Distinct());

Where this example gets a unique List of all ItemName and then unions this result, with a unique List of all OrderName.

Intersect

The Intersect operator produces the set intersection of two sequences.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; Intersect&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; first,
    IEnumerable&lt;T&gt; second);

So lets see a real world example (using the attached demo project and the _itemList and _orderList List local data sources)

var inter = (from i <span class="code-keyword">in</span> _itemList select i.ItemID).Distinct()
             .Intersect((from o <span class="code-keyword">in</span> _orderList select o.OrderID).Distinct());

Where this example gets a unique List of all Item ItemID values and then Intersect this result, with a unique List of all Order OrderID values. The result is a List of ints that are common to both the Item and Order List.

Except

The Except operator produces the set difference between two sequences.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; Except&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; first,
    IEnumerable&lt;T&gt; second);

So let's see a real world example (using the attached demo project and the _itemList and _orderList List local data sources)

 var inter = (from i <span class="code-keyword">in</span> _itemList select i.ItemID).Distinct()
             .Intersect((from o <span class="code-keyword">in</span> _orderList select o.OrderID).Distinct());

Where this example gets a unique List of all Item ItemID values and then Intersect this result, with a unique List of all Order OrderID values. The result is a List of ints that are common to both the Item and Order List.

Conversion (ToSequence / ToArray / ToList / ... ) Operators

The Set operators are made up of seven parts:

ToSequence

The ToSequence operator returns its argument typed as IEnumerable<T>.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; ToSequence&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source);

So let's see a real world example (using the attached demo project and the _itemList List local data source)

var query = _itemList.ToSequence().Where(i =&gt; i.Category.Equals(
    <span class="code-string">"</span><span class="code-string">Entertainment"</span>));

Where this example takes a List of Item and converts it to a Sequence and then grabs all elements whos Category is "Entertainment".

ToArray

The ToArray operator creates an array from a sequence.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> T[] ToArray&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source);

So let's see a real world example (using the attached demo project and the _itemList List local data source)

var query = _itemList.ToArray().Where(i =&gt; i.Category.Equals(<span class="code-string">"</span><span class="code-string">Food"</span>));

Where this example takes a List of Item and converts it to a array and then grabs all elements whos Category is "Food".

ToList

The ToList operator creates a List<T> from a sequence.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> List&lt;T&gt; ToList&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source);

So let's see a real world example (using the attached demo project and the _itemList List local data source)

var query = _itemList.ToList().Where(i =&gt; i.ItemID &gt; <span class="code-digit">5</span>).Reverse();

Where this example takes a source List of Item and converts it to a List and then grabs all elements whos ItemID > 5 and reverse it, so higher numbers are at start.

ToDictionary

The ToDictionary operator creates a Dictionary<K,E> from a sequence.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> Dictionary&lt;K, T&gt; ToDictionary&lt;T, K&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> Dictionary&lt;K, T&gt; ToDictionary&lt;T, K&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector,
    IEqualityComparer&lt;K&gt; comparer);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> Dictionary&lt;K, E&gt; ToDictionary&lt;T, K, E&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector,
    Func&lt;T, E&gt; elementSelector);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> Dictionary&lt;K, E&gt; ToDictionary&lt;T, K, E&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, K&gt; keySelector,
    Func&lt;T, E&gt; elementSelector,
    IEqualityComparer&lt;K&gt; comparer);

So let's see a real world example (using the attached demo project where a simple 2D array is used)

 var scoreRecords = <span class="code-keyword">new</span> [] { <span class="code-keyword">new</span> {Name = <span class="code-string">"</span><span class="code-string">Alice"</span>, Score = <span class="code-digit">50</span>},
                             <span class="code-keyword">new</span> {Name = <span class="code-string">"</span><span class="code-string">Bob"</span> , Score = <span class="code-digit">40</span>},
                             <span class="code-keyword">new</span> {Name = <span class="code-string">"</span><span class="code-string">Cathy"</span>, Score = <span class="code-digit">45</span>}
                           };
var scoreRecordsDict = scoreRecords.ToDictionary(sr =&gt; sr.Name);

Where this example creates a new 2D Array and converts that to a key/value Dictionary pair object.

ToLookup

The ToLookup operator creates a Lookup<K, T> from a sequence. I'll leave this up to the reader to explore.

OfType

The OfType operator filters the elements of a sequence based on a type.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> IEnumerable&lt;T&gt; OfType&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable source);

So let's see a real world example (using the attached demo project where a simple array is used)

<span class="code-keyword">object</span>[] numbers = { <span class="code-keyword">null</span>, <span class="code-digit">1</span>.<span class="code-digit">0</span>, <span class="code-string">"</span><span class="code-string">two"</span>, <span class="code-digit">3</span>, <span class="code-digit">4</span>.0f, <span class="code-digit">5</span>, <span class="code-string">"</span><span class="code-string">six"</span>, <span class="code-digit">7</span>.<span class="code-digit">0</span> };
var doubles = numbers.OfType&lt;double&gt;();

Where this example creates a new Array of varying objects, and then the OfType is used to grab only those that are of type Double.

Cast

The Cast operator casts the elements of a sequence to a given type. I'll leave this up to the reader to explore.

Equal Operator

The EqualAll operator checks whether two sequences are equal.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> <span class="code-keyword">bool</span> EqualAll&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; first,
    IEnumerable&lt;T&gt; second);

So let's see a real world example (using the attached demo project and the _itemList and _orderList List local data sources)

This is a Not Equal Example:

var eq = (from i <span class="code-keyword">in</span> _itemList select i.ItemID).Distinct().EqualAll((
    from o <span class="code-keyword">in</span> _orderList select o.OrderID).Distinct());

Where this example gets all Item object ItemID and the same for all the Order object OrderID and sees if the entire sequence is equal. They are not, as the Item List contains more elements than the Order List, as such there are certain ItemID that dont appear in the Order List.

This is an Equal Example:

<span class="code-keyword">int</span>[] scoreRecords1 = <span class="code-keyword">new</span> [] { <span class="code-digit">10</span>,<span class="code-digit">20</span> };
<span class="code-keyword">int</span>[] scoreRecords2 = <span class="code-keyword">new</span> [] { <span class="code-digit">10</span>,<span class="code-digit">20</span> };
 
var eq2 = scoreRecords1.EqualAll(scoreRecords2);

Where this example creates two new arrays, which have the same elements, and as such when they are compared using the EqualAll they are considered to be equal.

Element (First / FirstOrDefault / ... ) Operators

The Set operators are made up of nine parts:

First

The First operator returns the first element of a sequence.

<span class="code-keyword">public</span> <span class="code-keyword">static</span> T First&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source);
 
<span class="code-keyword">public</span> <span class="code-keyword">static</span> T First&lt;T&gt;(
    <span class="code-keyword">this</span> IEnumerable&lt;T&gt; source,
    Func&lt;T, bool&gt; predicate);

The First operator enumerates the source sequence and returns the first element for which the predicate function returns true. If no predicate function is specified, the First operator simply returns the first element of the sequence.

So let's see a real world example (using the attached demo project and the _itemList List local data source)

string itemName = "War of the worlds DVD";
Item itm = _itemList.First(i => i.ItemName ==

抱歉!评论已关闭.