LINQ to Objects
Lessons 35 and 36 explain how you can use Visual Studio’s wizards to build simple database
programs. They show one of many ways to connect a program to a data source.
Language-Integrated Query (LINQ) provides another method for bridging the gap between a
program and data. Instead of simply providing another way to access data in a database, how-
ever, LINQ can help a program access data stored in many places. LINQ lets a program access
data stored in databases, arrays, collections, or files in basically the same way.
LINQ provides four basic technologies that give you access to data stored in various places:
LINQ to SQL
Data stored in SQL Server databases
LINQ to Dataset
Data stored in other databases
LINQ to XML
Data stored in XML (eXtensible Markup Language) files
LINQ to Objects
Data stored in collections, lists, arrays, strings, files, and so forth
In this lesson you learn how to use LINQ to Objects. You learn how to extract data from lists,
collections, and arrays, and how to process the results.
LINQ BASICS
Using LINQ to process data takes three steps:
1. Create a data source.
2. Build a query to select data from the data source.
3. Execute the query and process the result.
You might expect the third step to be two separate steps, “Execute the query” and “Process the
result.” In practice, however, LINQ doesnt actually execute the query until it must when
the program tries to access the results. This is called deferred execution.
37
596906c37.indd 411 4/7/10 12:34:59 PM
412
LESSON 37 LINQ to objects
The following code displays the even numbers between 0 and 99:
// Display the even numbers between 0 and 99.
private void Form1_Load(object sender, EventArgs e)
{
// 1. Create the data source.
int[] numbers = new int[100];
for (int i = 0; i < 100; i++)
{
numbers[i] = i;
}
// 2. Build a query to select data from the data source.
var evenQuery =
from int num in numbers
where (num % 2 == 0)
select num;
// 3. Execute the query and process the result.
foreach (int num in evenQuery)
{
Console.WriteLine(num.ToString());
}
}
The program starts by creating the data source: an array containing the numbers 0 through 99. In
this example the data source is quite simple, but in other programs it could be much more complex.
Instead of an array of numbers, it could be a list of
Customer objects, or an array of Order objects
that contain lists of
OrderItem objects.
Next the program builds a query to select the even numbers from the list. I explain queries in more
detail later, but the following list describes the key pieces of this query:
var
This is the data type of whatever is returned by the query. In this example, the result
will be an
IEnumerable<int> but in general the results of LINQ queries can have some very
strange data types. Rather than trying to figure out what a query will return, most developers
use the implicit data type
var. The var keyword tells the C# compiler to figure out what the
data type is and use that so you don’t need to use a specific data type.
evenQuery
This is the name the code is giving to the query. You can think of it as a vari-
able that represents the result that LINQ will later produce.
from int num in numbers
This means the query will select data from the numbers
array. It will use the
int variable num to range over the values in the array. Because num
ranges over the values, it is called the query’s range variable. (If you omit the
int data type,
the compiler will implicitly figure out its data type.)
where (num % 2 == 0)
This is the query’s where clause. It determines which items are
selected from the array. This example selects the even numbers where
num mod 2 is 0.
select num
This tells the query to return whatever is in the range variable num for the
values that are selected. Often you will want to return the value of the range variable but you
could return something else such as
2 * num or a new object created with a constructor that
takes
num as a parameter.
596906c37.indd 412 4/7/10 12:34:59 PM
Where Clauses
413
I don’t recommend using var for variables in general if you can easily figure out
a more specific data type. When you use
var, you can’t be sure what data type
the compiler will use. That can lead to confusion if the compiler picks different
data types for variables that must later work together.
For example, in the following code the third statement is allowed because you
can store an
int value in a double but the fourth statement is not allowed
because a
double may not fit in an int:
var x = 1.2; // double.
var y = 1; // int.
x = y; // Allowed.
y = x; // Not allowed.
So, if you do know the data type, just use that instead of var.
In the final step to performing the query, the code loops through the result produced by LINQ. The
code displays each
int value in the Console window.
The following sections provide more detailed descriptions of some of the key pieces of a LINQ
query: where clauses, order by clauses, and select clauses.
WHERE CLAUSES
Probably the most common reason to use LINQ is to filter the data with a where clause. The where
clause can include normal Boolean expressions that use
&&, ||, >, and other Boolean operators. It
can use the range variable and any properties or methods that it provides (if it’s an object). It can
even perform calculations and invoke functions.
For example, the following query is similar to the earlier one that selects even numbers, except this
one’s where clause uses the
IsPrime function to select only prime numbers. (How the IsPrime func-
tion works isn’t important to this discussion, so it isn’t shown here. You can see it in the FindPrimes
program in this lesson’s download.)
The where clause is optional. If you omit it, the query selects all of the items in
its range.
var primeQuery =
from int num in numbers
where (IsPrime(num))
select num;
The FindCustomers example program shown in Figure 37-1 (and available in this chapters code
download on the web site) demonstrates several where clauses.
596906c37.indd 413 4/7/10 12:34:59 PM
414
LESSON 37 LINQ to objects
FIGURE 371
The following code shows the Customers class used by the FindCustomers program. It just
includes some auto-implemented properties and an overridden
ToString method that displays
the
Customers values.
class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public decimal Balance { get; set; }
public DateTime DueDate { get; set; }
public override string ToString()
{
return FirstName + “ “ + LastName + “ ” +
Balance.ToString(“C”) + “ ” + DueDate.ToString(“d”);
}
}
The following code shows how the FindCustomers program displays the same customer data
selected with different where clauses:
// Display customers selected in various ways.
private void Form1_Load(object sender, EventArgs e)
{
DateTime today = new DateTime(2010, 4, 1);
//DateTime today = DateTime.Today;
this.Text = “FindCustomers (“ + today.ToString(“d”) + “)“;
// Make the customers.
Customer[] customers =
{
new Customer() { FirstName=“Ann”, LastName=“Ashler”,
Balance = 100, DueDate = new DateTime(2010, 3, 10)},
new Customer() { FirstName=“Bob”, LastName=“Boggart”,
Balance = 150, DueDate = new DateTime(2010, 2, 5)},
// ... Other Customers omitted ...
};
596906c37.indd 414 4/7/10 12:35:00 PM
Where Clauses
415
// Display all customers.
allListBox.DataSource = customers;
// Display customers with negative balances.
var negativeQuery =
from Customer cust in customers
where cust.Balance < 0
select cust;
negativeListBox.DataSource = negativeQuery.ToArray();
// Display customers who owe at least $50.
var owes50Query =
from Customer cust in customers
where cust.Balance <= -50
select cust;
owes50listBox.DataSource = owes50Query.ToArray();
// Display customers who owe at least $50
// and are overdue at least 30 days.
var overdueQuery =
from Customer cust in customers
where (cust.Balance <= -50) &&
(DateTime.Now.Subtract(cust.DueDate).TotalDays > 30)
select cust;
overdueListBox.DataSource = overdueQuery.ToArray();
}
The program starts by creating a DateTime named today and setting it equal to April 1, 2010. In a
real application you would probably use the current date (commented out), but this program uses that
specific date so it works well with the sample data. The program then displays the date in its title bar
(so you can compare it to the
Customers’ due dates) and creates an array of Customer objects.
Next the code sets the
allListBox control’s DataSource property to the array so that listbox displays
all of the
Customer objects. The Customer class’s overridden ToString method makes it display each
Customers name, balance, and due date.
The program then executes the following LINQ query:
// Display customers with negative balances.
var negativeQuery =
from Customer cust in customers
where cust.Balance < 0
select cust;
negativeListBox.DataSource = negativeQuery.ToArray();
This query’s where clause selects Customers with Balance properties less than 0. The query returns
an
IEnumerable, but a ListBox’s DataSource property requires an IList or IListSource so the
program calls the result’s
ToArray method to convert it into an array that the DataSource property
can handle.
After displaying this result, the program executes two other LINQ queries and displays their results
similarly. The first query selects
Customers who owe at least $50. The final query selects Customers
who owe at least $50 and who have a
DueDate more than 30 days in the past.
596906c37.indd 415 4/7/10 12:35:00 PM
..................Content has been hidden....................

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