Tải bản đầy đủ (.pdf) (58 trang)

Apress pro LINQ Language Integrated Query in C# 2008 phần 4 ppt

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.02 MB, 58 trang )

160
CHAPTER 5
■ NONDEFERRED OPERATORS
This code is functionally equivalent to the previous example. Instead of calling the Where operator
to ensure a single element is in the sequence, I can provide the same sequence filtering operation in
the Single operator itself. This should return the only element in the input sequence whose id is 3.
Here are the results:
Anders Hejlsberg
Remember, if either prototype of the Single operator ends up with no element to return, an
InvalidOperationException is thrown. To avoid this, use the SingleOrDefault operator.
SingleOrDefault
The SingleOrDefault operator is similar to the Single operator except for how it behaves when an
element is not found.
Prototypes
There are two prototypes I cover.
The First SingleOrDefault Prototype
public static T SingleOrDefault<T>(
this IEnumerable<T> source);
This version of the prototype returns the only element found in the input sequence. If the sequence
is empty, default(T) is returned. For reference and nullable types, the default value is null. If more
than one element is found, an InvalidOperationException is thrown.
The second prototype of the SingleOrDefault operator allows you to pass a predicate to deter-
mine which element should be returned.
The Second SingleOrDefault Prototype
public static T SingleOrDefault<T>(
this IEnumerable<T> source,
Func<T, bool> predicate);
Exceptions
ArgumentNullException is thrown if any arguments are null.
InvalidOperationException is thrown if the operator finds more than one element for which the
predicate returns true.


Examples
Listing 5-30 is an example of the first SingleOrDefault prototype where no element is found. I have
to get an empty sequence to do this. I’ll use the Where operator and provide a key comparison for a
key that doesn’t exist for this purpose.
Rattz_789-3.book Page 160 Tuesday, October 16, 2007 2:21 PM
CHAPTER 5 ■ NONDEFERRED OPERATORS
161
Listing 5-30. Calling the First SingleOrDefault Prototype Where an Element Is Not Found
Employee emp = Employee.GetEmployeesArray()
.Where(e => e.id == 5).SingleOrDefault();
Console.WriteLine(emp == null ? "NULL" :
string.Format("{0} {1}", emp.firstName, emp.lastName));
I queried for the employee whose id is 5 since I know none exists, so an empty sequence will be
returned. Unlike the Single operator, the SingleOrDefault operator handles empty sequences just
fine. Here are the results:
NULL
Listing 5-31 is the same example where a single element is found. I use the Where operator to
provide a sequence with just one element.
Listing 5-31. Calling the First SingleOrDefault Prototype Where an Element Is Found
Employee emp = Employee.GetEmployeesArray()
.Where(e => e.id == 4).SingleOrDefault();
Console.WriteLine(emp == null ? "NULL" :
string.Format("{0} {1}", emp.firstName, emp.lastName));
This time I specify an id I know exists. Here are the results for the code when an element is
found:
David Lightman
As you can see, the employee has been found. For the second SingleOrDefault prototype, shown
in Listing 5-32, I specify an id that I know exists. Instead of using the Where operator, I embed the filter
into the SingleOrDefault operator call.
Listing 5-32. Calling the Second SingleOrDefault Prototype Where an Element Is Found

Employee emp = Employee.GetEmployeesArray()
.SingleOrDefault(e => e.id == 4);
Console.WriteLine(emp == null ? "NULL" :
string.Format("{0} {1}", emp.firstName, emp.lastName));
This example is functionally equivalent to the previous example except instead of filtering the
elements using the Where operator, I filter them by passing a predicate to the SingleOrDefault oper-
ator. Here are the results:
David Lightman
Rattz_789-3.book Page 161 Tuesday, October 16, 2007 2:21 PM
162
CHAPTER 5
■ NONDEFERRED OPERATORS
Now I will try that with a predicate that will not find a match, as shown in Listing 5-33.
Listing 5-33. Calling the Second LastOrDefault Prototype Where an Element Is Not Found
Employee emp = Employee.GetEmployeesArray()
.SingleOrDefault(e => e.id == 5);
Console.WriteLine(emp == null ? "NULL" :
string.Format("{0} {1}", emp.firstName, emp.lastName));
Since there is no element whose id is 5, no elements are found. Here are the results:
NULL
While no elements were found in the sequence, the SingleOrDefault operator handled the situation
gracefully instead of throwing an exception.
ElementAt
The ElementAt operator returns the element from the source sequence at the specified index.
Prototypes
There is one prototype I cover.
The ElementAt Prototype
public static T ElementAt<T>(
this IEnumerable<T> source,
int index);

If the sequence implements IList<T>, the IList interface is used to retrieve the indexed element
directly. If the sequence does not implement IList<T>, the sequence is enumerated until the indexed
element is reached. An ArgumentOutOfRangeException is thrown if the index is less than zero or greater
than or equal to the number of elements in the sequence.
■Note In C#, indexes are zero-based. This means the first element’s index is zero. The last element’s index is
the sequence’s count minus one.
Exceptions
ArgumentNullException is thrown if the source argument is null.
ArgumentOutOfRangeException is thrown if the index is less than zero or greater than or equal to
the number of elements in the sequence.
Examples
Listing 5-34 is an example calling the only prototype of the ElementAt operator.
Rattz_789-3.book Page 162 Tuesday, October 16, 2007 2:21 PM
CHAPTER 5 ■ NONDEFERRED OPERATORS
163
Listing 5-34. Calling the ElementAt Operator
Employee emp = Employee.GetEmployeesArray()
.ElementAt(3);
Console.WriteLine("{0} {1}", emp.firstName, emp.lastName);
I specified that I want the element whose index is 3, which is the fourth element. Here are the
results of the query:
David Lightman
ElementAtOrDefault
The ElementAtOrDefault operator returns the element from the source sequence at the specified
index.
Prototypes
There is one prototype I cover.
The ElementAtOrDefault Prototype
public static T ElementAtOrDefault<T>(
this IEnumerable<T> source,

int index);
If the sequence implements IList<T>, the IList interface is used to retrieve the indexed element
directly. If the sequence does not implement IList<T>, the sequence will be enumerated until the
indexed element is reached.
If the index is less than zero or greater than or equal to the number of elements in the sequence,
default(T) is returned. For reference and nullable types, the default value is null. This is the behavior
that distinguishes it from the ElementAt operator.
Exceptions
ArgumentNullException is thrown if the source argument is null.
Examples
Listing 5-35 is an example calling the ElementAtOrDefault operator when the index is valid.
Listing 5-35. Calling the ElementAtOrDefault Operator with a Valid Index
Employee emp = Employee.GetEmployeesArray()
.ElementAtOrDefault(3);
Console.WriteLine(emp == null ? "NULL" :
string.Format("{0} {1}", emp.firstName, emp.lastName));
Here are the results of the query:
David Lightman
Rattz_789-3.book Page 163 Tuesday, October 16, 2007 2:21 PM
164
CHAPTER 5
■ NONDEFERRED OPERATORS
Just as expected, the element at index 3 is retrieved. Now I will try a query with an invalid index
using the code in Listing 5-36.
Listing 5-36. Calling the ElementAtOrDefault Operator with an Invalid Index
Employee emp = Employee.GetEmployeesArray()
.ElementAtOrDefault(5);
Console.WriteLine(emp == null ? "NULL" :
string.Format("{0} {1}", emp.firstName, emp.lastName));
There is no element whose index is 5. Here are the results of the query:

NULL
Quantifiers
The following quantifier operators allow you to perform quantification type operations on input
sequences.
Any
The Any operator returns true if any element of an input sequence matches a condition.
Prototypes
There are two prototypes I cover.
The First Any Prototype
public static bool Any<T>(
this IEnumerable<T> source);
This prototype of the Any operator will return true if the source input sequence contains any
elements. The second prototype of the Any operator enumerates the source input sequence and
returns true if at least one element in the input sequence causes the predicate method delegate to
return true. The source input sequence enumeration halts once the predicate returns true.
The Second Any Prototype
public static bool Any<T>(
this IEnumerable<T> source,
Func<T, bool> predicate);
Exceptions
ArgumentNullException is thrown if any of the arguments are null.
Examples
First I will try the case of an empty sequence, as shown in Listing 5-37. I will use the Empty operator I
covered in the previous chapter.
Rattz_789-3.book Page 164 Tuesday, October 16, 2007 2:21 PM
CHAPTER 5 ■ NONDEFERRED OPERATORS
165
Listing 5-37. First Any Prototype Where No Elements Are in the Source Input Sequence
bool any = Enumerable.Empty<string>().Any();
Console.WriteLine(any);

Here are the results of this code:
False
Next I will try the same prototype but, this time, with elements in the input sequence, as shown
in Listing 5-38.
Listing 5-38. First Any Prototype Where Elements Are in the Source Input Sequence
string[] presidents = {
"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland",
"Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield",
"Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson",
"Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",
"Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft",
"Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};
bool any = presidents.Any();
Console.WriteLine(any);
Here are the results of this code:
True
For the next example, I use the second prototype, first with no elements matching the predicate, as
shown in Listing 5-39.
Listing 5-39. Second Any Prototype Where No Elements Cause the Predicate to Return True
string[] presidents = {
"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland",
"Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield",
"Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson",
"Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",
"Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft",
"Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};
bool any = presidents.Any(s => s.StartsWith("Z"));
Console.WriteLine(any);
I specify that I want the presidents that start with the string "Z". Since there are none, an empty
sequence will be returned causing the Any operator to return false. The results are as one would expect:

False
Rattz_789-3.book Page 165 Tuesday, October 16, 2007 2:21 PM
166
CHAPTER 5
■ NONDEFERRED OPERATORS
Finally, I try an example of the second prototype with a predicate that should return true for at
least one element, as shown in Listing 5-40.
Listing 5-40. Second Any Prototype Where at Least One Element Causes the Predicate to Return True
string[] presidents = {
"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland",
"Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield",
"Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson",
"Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",
"Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft",
"Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};
bool any = presidents.Any(s => s.StartsWith("A"));
Console.WriteLine(any);
And finally, here are the results:
True
All
The All operator returns true if every element in the input sequence matches a condition.
Prototypes
There is one prototype I cover.
The All Prototype
public static bool All<T>(
this IEnumerable<T> source,
Func<T, bool> predicate);
The All operator enumerates the source input sequence and returns true only if the predicate
returns true for every element in the sequence. Once the predicate returns false, the enumeration
will cease.

Exceptions
ArgumentNullException is thrown if any of the arguments are null.
Examples
In Listing 5-41 I begin with a predicate with which I know at least some of the elements will return
false.
Listing 5-41. All Prototype Where Not Every Element Causes the Predicate to Return True
string[] presidents = {
"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland",
"Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield",
"Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson",
"Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",
Rattz_789-3.book Page 166 Tuesday, October 16, 2007 2:21 PM
CHAPTER 5 ■ NONDEFERRED OPERATORS
167
"Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft",
"Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};
bool all = presidents.All(s => s.Length > 5);
Console.WriteLine(all);
Since I know not every president in the array has a length of more than five characters, I know
that predicate will return false for some elements. Here is the output:
False
Now I will try a case where I know every element will cause the predicate to return true, as
shown in Listing 5-42.
Listing 5-42. All Prototype Where Every Element Causes the Predicate to Return True
string[] presidents = {
"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland",
"Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield",
"Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson",
"Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",
"Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft",

"Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};
bool all = presidents.All(s => s.Length > 3);
Console.WriteLine(all);
Since I know every president’s name has at least four characters, the All operator should return
true. Here is the output:
True
Contains
The Contains operator returns true if any element in the input sequence matches the specified value.
Prototypes
There are two prototypes I cover.
The First Contains Prototype
public static bool Contains<T>(
this IEnumerable<T> source,
T value);
This prototype of the Contains operator first checks the source input sequence to see if it imple-
ments the ICollection<T> interface, and if it does, it calls the Contains method of the sequence’s
implementation. If the sequence does not implement the ICollection<T> interface, it enumerates
the source input sequence to see if any element matches the specified value. Once it finds an element
that does match, the enumeration halts.
Rattz_789-3.book Page 167 Tuesday, October 16, 2007 2:21 PM
168
CHAPTER 5
■ NONDEFERRED OPERATORS
The specified value is compared to each element using the EqualityComparer<K>.Default
default equality comparison class.
The second prototype is like the previous except an IEqualityComparer<T> object can be speci-
fied. If this prototype is used, each element in the sequence is compared to the passed value using
the passed equality comparison object.
The Second Contains Prototype
public static bool Contains<T>(

this IEnumerable<T> source,
T value,
IEqualityComparer<T> comparer);
Exceptions
ArgumentNullException is thrown if the source input sequence is null.
Examples
For an example of the first prototype, I begin with a value that I know is not in my input sequence, as
shown in Listing 5-43
Listing 5-43. First Contains Prototype Where No Element Matches the Specified Value
string[] presidents = {
"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland",
"Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield",
"Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson",
"Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",
"Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft",
"Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};
bool contains = presidents.Contains("Rattz");
Console.WriteLine(contains);
Since there is no element whose value is "Rattz" in the array, the contains variable should be
false. Here is the output:
False
In Listing 5-44, I know an element will match my specified value.
Listing 5-44. First Contains Prototype Where an Element Matches the Specified Value
string[] presidents = {
"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland",
"Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield",
"Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson",
"Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",
"Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft",
"Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};

Rattz_789-3.book Page 168 Tuesday, October 16, 2007 2:21 PM
CHAPTER 5 ■ NONDEFERRED OPERATORS
169
bool contains = presidents.Contains("Hayes");
Console.WriteLine(contains);
Since there is an element with the value of "Hayes", the contains variable should be true. Here
is the output:
True
For an example of the second Contains operator prototype, I will use my common
MyStringifiedNumberComparer class. I will check an array of numbers in string format for a number
in string format that is technically unequal to any element in the array, but because I use my equality
comparison class, the appropriate element will be found. Listing 5-45 shows the example.
Listing 5-45. Second Contains Prototype Where an Element Matches the Specified Value
string[] stringifiedNums = {
"001", "49", "017", "0080", "00027", "2" };
bool contains = stringifiedNums.Contains("0000002",
new MyStringifiedNumberComparer());
Console.WriteLine(contains);
Since I am looking for an element with a value of "0000002", and because my equality compar-
ison object will be used, which will convert that string value as well as all of the sequence elements
to an integer before making the comparison, and because my sequence contains the element "2",
the contains variable should be true. Let’s take a look at the results:
True
Now I will try the same example except this time I will query for an element that I know doesn’t
exist. The code is shown in Listing 5-46.
Listing 5-46. Second Contains Prototype Where an Element Does Not Match the Specified Value
string[] stringifiedNums = {
"001", "49", "017", "0080", "00027", "2" };
bool contains = stringifiedNums.Contains("000271",
new MyStringifiedNumberComparer());

Console.WriteLine(contains);
Since I know that none of the elements when converted to an integer equals 271, I search the
array for "000271". Here are the results:
False
Rattz_789-3.book Page 169 Tuesday, October 16, 2007 2:21 PM
170
CHAPTER 5
■ NONDEFERRED OPERATORS
Aggregate
The following aggregate operators allow you to perform aggregate operations on the elements of an
input sequence.
Count
The Count operator returns the number of elements in the input sequence.
Prototypes
There are two prototypes I cover.
The First Count Prototype
public static int Count<T>(
this IEnumerable<T> source);
This prototype of the Count operator returns the total number of elements in the source input
sequence by first checking the input sequence to see if it implements the ICollection<T> interface,
and if so, it obtains the sequence’s count using the implementation of that interface. If the source
input sequence does not implement the ICollection<T> interface, it enumerates the entire input
sequence counting the number of elements.
The second prototype of the Count operator enumerates the source input sequence and counts
every element that causes the predicate method delegate to return true.
The Second Count Prototype
public static int Count<T>(
this IEnumerable<T> source,
Func<T, bool> predicate);
Exceptions

ArgumentNullException is thrown if any argument is null.
OverflowException is thrown if the count exceeds the capacity of int.MaxValue.
Examples
Listing 5-47 begins with the first prototype. How many elements are there in the presidents sequence?
Listing 5-47. The First Count Prototype
string[] presidents = {
"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland",
"Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield",
"Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson",
"Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",
"Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft",
"Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};
int count = presidents.Count();
Console.WriteLine(count);
Rattz_789-3.book Page 170 Tuesday, October 16, 2007 2:21 PM
CHAPTER 5 ■ NONDEFERRED OPERATORS
171
Here are the results:
37
Now I will try an example of the second prototype, shown in Listing 5-48. I will count the number
of presidents beginning with the letter "J".
Listing 5-48. The Second Count Prototype
string[] presidents = {
"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland",
"Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield",
"Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson",
"Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",
"Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft",
"Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};
int count = presidents.Count(s => s.StartsWith("J"));

Console.WriteLine(count);
The results from this code are the following:
3
So what happens if the count exceeds the capacity of int.MaxValue? That’s what the LongCount
operator is for.
LongCount
The LongCount operator returns the number of elements in the input sequence as a long.
Prototypes
There are two prototypes I cover.
The First LongCount Prototype
public static long LongCount<T>(
this IEnumerable<T> source);
The first prototype of the LongCount operator returns the total number of elements in the source
input sequence by enumerating the entire input sequence and counting the number of elements.
The second prototype of the LongCount operator enumerates the source input sequence and
counts every element that causes the predicate method delegate to return true.
The Second LongCount Prototype
public static long LongCount<T>(
this IEnumerable<T> source,
Func<T, bool> predicate);
Rattz_789-3.book Page 171 Tuesday, October 16, 2007 2:21 PM
172
CHAPTER 5
■ NONDEFERRED OPERATORS
Exceptions
ArgumentNullException is thrown if any argument is null.
Examples
I will begin with an example of the first prototype, shown in Listing 5-49. I could just reiterate the
same two examples I use for the Count operator, changing the relevant parts to type long, but that
wouldn’t be very demonstrative of the operator. Since it isn’t feasible for me to have a sequence long

enough to require the LongCount operator, I use a standard query operator to generate one. Unfortu-
nately, the generation operators I cover in the previous chapter only allow you to specify the number
of elements to generate using an int. I have to concatenate a couple of those generated sequences
together to get enough elements to require the LongCount operator.
Listing 5-49. The First LongCount Prototype
long count = Enumerable.Range(0, int.MaxValue).
Concat(Enumerable.Range(0, int.MaxValue)).LongCount();
Console.WriteLine(count);
As you can see, I generated two sequences using the Range operator I cover in the previous chapter
and concatenated them together using the Concat operator also covered in the previous chapter.
■Caution This example takes a long time to run. On my machine, a P4 with 1GB of memory, it took approxi-
mately two and a half minutes.
Before you run that example, let me warn you that it takes a long time to run. Don’t be surprised
if it takes several minutes. After all, it has to generate two sequences, each with 2,147,483,647 elements.
Here are the results:
4294967294
If you try to run that same example using the Count operator, you will get an exception. Now I
will try an example of the second prototype. For this example, I use the same basic example as the
previous, except I specify a predicate that only returns true for integers greater than 1 and less than
4. This essentially means 2 and 3. Since I have two sequences with the same values, I should get a
count of 4, as shown in Listing 5-50.
Listing 5-50. An Example of the Second LongCount Prototype
long count = Enumerable.Range(0, int.MaxValue).
Concat(Enumerable.Range(0, int.MaxValue)).LongCount(n => n > 1 && n < 4);
Console.WriteLine(count);
This code is pretty much the same as the previous example except I have specified a predicate.
This example takes even longer to run than the previous example.
The results from this code are the following:
Rattz_789-3.book Page 172 Tuesday, October 16, 2007 2:21 PM
CHAPTER 5 ■ NONDEFERRED OPERATORS

173
4
Sum
The Sum operator returns the sum of numeric values contained in the elements of the input
sequence.
Prototypes
There are two prototypes I cover.
The First Sum Prototype
public static Numeric Sum(
this IEnumerable<Numeric> source);
The Numeric type must be one of int, long, double, or decimal or one of their nullable equivalents,
int?, long?, double?, or decimal?.
The first prototype of the Sum operator returns the sum of each element in the source input
sequence.
An empty sequence will return the sum of zero. The Sum operator will not include null values in
the result for Numeric types that are nullable.
The second prototype of the Sum operator behaves like the previous, except it will sum the value
selected from each element by the selector method delegate.
The Second Sum Prototype
public static Numeric Sum<T>(
this IEnumerable<T> source,
Func<T, Numeric> selector);
Exceptions
ArgumentNullException is thrown if any argument is null.
OverflowException is thrown if the sum is too large to be stored in the Numeric type if the Numeric
type is other than decimal or decimal?. If the Numeric type is decimal or decimal?, a positive or negative
infinity value is returned.
Examples
I will begin with an example of the first prototype, shown in Listing 5-51. First I generate a sequence
of integers using the Range operator, and then I use the Sum operator to sum them.

Listing 5-51. An Example of the First Sum Prototype
IEnumerable<int> ints = Enumerable.Range(1, 10);
foreach (int i in ints)
Console.WriteLine(i);
Console.WriteLine(" ");
int sum = ints.Sum();
Console.WriteLine(sum);
Rattz_789-3.book Page 173 Tuesday, October 16, 2007 2:21 PM
174
CHAPTER 5
■ NONDEFERRED OPERATORS
Here are the results:
1
2
3
4
5
6
7
8
9
10

55
Now I will try an example of the second prototype, shown in Listing 5-52. For this example, I use
the common EmployeeOptionEntry class and sum the count of the options for all employees.
Listing 5-52. An Example of the Second Sum Prototype
IEnumerable<EmployeeOptionEntry> options =
EmployeeOptionEntry.GetEmployeeOptionEntries();
long optionsSum = options.Sum(o => o.optionsCount);

Console.WriteLine("The sum of the employee options is: {0}", optionsSum);
Instead of trying to sum the entire element, which makes no sense in this example because it is
an employee object, I can use the second prototype’s element selector to retrieve just the member
I am interested in summing, which in this case is the optionsCount member. The results of this code
are the following:
The sum of the employee options is: 51504
Min
The Min operator returns the minimum value of an input sequence.
Prototypes
There are four prototypes I cover.
The First Min Prototype
public static Numeric Min(
this IEnumerable<Numeric> source);
The Numeric type must be one of int, long, double, or decimal or one of their nullable equivalents,
int?, long?, double?, or decimal?.
The first prototype of the Min operator returns the element with the minimum numeric value in
the source input sequence. If the element type implements the IComparable<T> interface, that inter-
face will be used to compare the elements. If the elements do not implement the IComparable<T>
interface, the nongeneric IComparable interface will be used.
An empty sequence, or one that contains only null values, will return the value of null.
Rattz_789-3.book Page 174 Tuesday, October 16, 2007 2:21 PM
CHAPTER 5 ■ NONDEFERRED OPERATORS
175
The second prototype of the Min operator behaves like the previous, except it is for non-Numeric
types.
The Second Min Prototype
public static T Min<T>(
this IEnumerable<T> source);
The third prototype is for Numeric types and is like the first, except now a selector method delegate
can be provided, allowing a member of each element in the input sequence to be compared while

searching for the minimum value in the input sequence and returning that minimum value.
The Third Min Prototype
public static Numeric Min<T>(
this IEnumerable<T> source,
Func<T, Numeric> selector);
The fourth prototype is for non-Numeric types and is like the second, except now a selector
method delegate can be provided, allowing a member of each element in the input sequence to be
compared while searching for the minimum value in the input sequence and returning that
minimum value.
The Fourth Min Prototype
public static S Min<T, S>(
this IEnumerable<T> source,
Func<T, S> selector);
Exceptions
ArgumentNullException is thrown if any argument is null.
InvalidOperationException is thrown if the source sequence is empty for the Numeric versions
of the prototypes if the type T is non-nullable, such as int, long, double, or decimal. If the types are
nullable, that is, int?, long?, double?, decimal?, a null is returned from the operator instead.
Examples
In the example of the first Min prototype, shown in Listing 5-53, I declare an array of integers and
return the minimum from it.
Listing 5-53. An Example of the First Min Prototype
int[] myInts = new int[] { 974, 2, 7, 1374, 27, 54 };
int minInt = myInts.Min();
Console.WriteLine(minInt);
That is a pretty trivial example. The following is the result:
2
For my example of the second prototype, shown in Listing 5-54, I will just call the Min operator
on my standard presidents array. This should return the element with the lowest value, alphabeti-
cally speaking.

Rattz_789-3.book Page 175 Tuesday, October 16, 2007 2:21 PM
176
CHAPTER 5
■ NONDEFERRED OPERATORS
Listing 5-54. An Example of the Second Min Prototype
string[] presidents = {
"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland",
"Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield",
"Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson",
"Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",
"Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft",
"Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};
string minName = presidents.Min();
Console.WriteLine(minName);
This example provides the following results:
Adams
While this may be the same output that calling the First operator would provide, this is only
because the presidents array is already sequenced alphabetically. Had the array been in some other
order, or disordered, the results would have still been Adams.
For the example of the third prototype of the Min operator, I use my common Actor class to find
the earliest actor birth year by calling the Min operator on the birth year.
Listing 5-55 is the code calling the Min operator.
Listing 5-55. An Example of the Third Min Prototype
int oldestActorAge = Actor.GetActors().Min(a => a.birthYear);
Console.WriteLine(oldestActorAge);
And the birth year of the actor with the most plastic surgery, I mean, the earliest birth year is the
following:
1960
For an example of the fourth Min prototype, shown in Listing 5-56, I obtain the last name of the
actor that would come first alphabetically using my common Actor class.

Listing 5-56. An Example of the Fourth Min Prototype
string firstAlphabetically = Actor.GetActors().Min(a => a.lastName);
Console.WriteLine(firstAlphabetically);
And the Oscar goes to
Bullock
Max
The Max operator returns the maximum value of an input sequence.
Rattz_789-3.book Page 176 Tuesday, October 16, 2007 2:21 PM
CHAPTER 5 ■ NONDEFERRED OPERATORS
177
Prototypes
There are four prototypes I cover.
The First Max Prototype
public static Numeric Max(
this IEnumerable<Numeric> source);
The Numeric type must be one of int, long, double, or decimal or one of their nullable equiva-
lents, int?, long?, double?, or decimal?.
The first prototype of the Max operator returns the element with the maximum numeric value in
the source input sequence. If the element type implements the IComparable<T> interface, that inter-
face will be used to compare the elements. If the elements do not implement the IComparable<T>
interface, the nongeneric IComparable interface will be used.
An empty sequence, or one that contains only null values, will return the value of null.
The second prototype of the Max operator behaves like the previous, except it is for non-Numeric
types.
The Second Max Prototype
public static T Max<T>(
this IEnumerable<T> source);
The third prototype is for Numeric types and like the first, except now a selector method delegate
can be provided, allowing a member of each element in the input sequence to be compared while
searching for the maximum value in the input sequence and returning that maximum value.

The Third Max Prototype
public static Numeric Max<T>(
this IEnumerable<T> source,
Func<T, Numeric> selector);
The fourth prototype is for non-Numeric types and is like the second, except now a selector method
delegate can be provided, allowing a member of each element in the input sequence to be compared
while searching for the maximum value in the input sequence and returning that maximum value.
The Fourth Max Prototype
public static S Max<T, S>(
this IEnumerable<T> source,
Func<T, S> selector);
Exceptions
ArgumentNullException is thrown if any argument is null.
InvalidOperationException is thrown if the source sequence is empty for the Numeric versions
of the prototypes if the type T is non-nullable, such as int, long, double, or decimal. If the types are
nullable, such as int?, long?, double?, decimal?, a null is returned from the operator instead.
Examples
As an example of the first Max prototype, shown in Listing 5-57, I declare an array of integers and
return the maximum from it.
Rattz_789-3.book Page 177 Tuesday, October 16, 2007 2:21 PM
178
CHAPTER 5
■ NONDEFERRED OPERATORS
Listing 5-57. An Example of the First Max Prototype
int[] myInts = new int[] { 974, 2, 7, 1374, 27, 54 };
int maxInt = myInts.Max();
Console.WriteLine(maxInt);
The results are the following:
1374
For an example of the second prototype, shown in Listing 5-58, I just call the Max operator on my

standard presidents array.
Listing 5-58. An Example of the Second Max Prototype
string[] presidents = {
"Adams", "Arthur", "Buchanan", "Bush", "Carter", "Cleveland",
"Clinton", "Coolidge", "Eisenhower", "Fillmore", "Ford", "Garfield",
"Grant", "Harding", "Harrison", "Hayes", "Hoover", "Jackson",
"Jefferson", "Johnson", "Kennedy", "Lincoln", "Madison", "McKinley",
"Monroe", "Nixon", "Pierce", "Polk", "Reagan", "Roosevelt", "Taft",
"Taylor", "Truman", "Tyler", "Van Buren", "Washington", "Wilson"};
string maxName = presidents.Max();
Console.WriteLine(maxName);
This provides the following results:
Wilson
Again, like I mentioned in the equivalent example for the Min operator, while this example
provides the same result that the Last operator would, this is only because the presidents array is
already ordered alphabetically.
For the example of the third prototype of the Max operator, I use my common Actor class to find
the latest actor birth year by calling the Max operator on the birth year.
Listing 5-59 is the code calling the Max operator.
Listing 5-59. An Example of the Third Max Prototype
int youngestActorAge = Actor.GetActors().Max(a => a.birthYear);
Console.WriteLine(youngestActorAge);
And the latest actor birth year in my Actor class is the following:
1968
For an example of the fourth Max prototype, shown in Listing 5-60, I will obtain the last name of
the actor that would come last alphabetically using the same Actor class as previously.
Rattz_789-3.book Page 178 Tuesday, October 16, 2007 2:21 PM
CHAPTER 5 ■ NONDEFERRED OPERATORS
179
Listing 5-60. An Example of the Fourth Max Prototype

string lastAlphabetically = Actor.GetActors().Max(a => a.lastName);
Console.WriteLine(lastAlphabetically);
The results are the following:
Wilson
Hey, that is the same result I had for my second example where I used the array of the names of
the U.S. presidents. How creepy. That Dignan is always up to no good!
Average
The Average operator returns the average of numeric values contained in the elements of the input
sequence.
Prototypes
There are two prototypes I cover.
The First Average Prototype
public static Result Average(
this IEnumerable<Numeric> source);
The Numeric type must be one of int, long, double, or decimal or one of their nullable equiva-
lents, int?, long?, double?, or decimal?. If the Numeric type is int or long, the Result type will be
double. If the Numeric type is int? or long?, the Result type will be double?. Otherwise, the Result type
will be the same as the Numeric type.
The first prototype of the Average operator enumerates the input source sequence of Numeric
type elements, creating an average of the elements themselves.
The second prototype of the Average operator enumerates the source input sequence and deter-
mines the average for the member returned by the selector for every element in the input source
sequence.
The Second Average Prototype
public static Result Average<T>(
this IEnumerable<T> source,
Func<T, Numeric> selector);
Exceptions
ArgumentNullException is thrown if any argument is null.
OverflowException is thrown if the sum of the averaged values exceeds the capacity of a long for

Numeric types int, int?, long, and long?.
Examples
I will begin with an example of the first prototype, shown in Listing 5-61. For this example, I use the
Range operator to create a sequence of integers, and then I will average them.
Rattz_789-3.book Page 179 Tuesday, October 16, 2007 2:21 PM
180
CHAPTER 5
■ NONDEFERRED OPERATORS
Listing 5-61. An Example of the First Average Prototype
IEnumerable<int> intSequence = Enumerable.Range(1, 10);
Console.WriteLine("Here is my sequnece of integers:");
foreach (int i in intSequence)
Console.WriteLine(i);
double average = intSequence.Average();
Console.WriteLine("Here is the average: {0}", average);
Here are the results:
Here is my sequnece of integers:
1
2
3
4
5
6
7
8
9
10
Here is the average: 5.5
Now I will try an example of the second prototype, which will access a member of the element.
For this example, shown in Listing 5-62, I use my common EmployeeOptionEntry class.

Listing 5-62. An Example of the Second Average Prototype
IEnumerable<EmployeeOptionEntry> options =
EmployeeOptionEntry.GetEmployeeOptionEntries();
Console.WriteLine("Here are the employee ids and their options:");
foreach (EmployeeOptionEntry eo in options)
Console.WriteLine("Employee id: {0}, Options: {1}", eo.id, eo.optionsCount);
// Now I'll get the average of the options.
double optionAverage = options.Average(o => o.optionsCount);
Console.WriteLine("The average of the employee options is: {0}", optionAverage);
First I retrieve the EmployeeOptionEntry objects. Then I enumerate through the sequence of
objects and display each. At the end, I calculate the average and display it. The results of this code are
the following:
Here are the employee ids and their options:
Employee id: 1, Options: 2
Employee id: 2, Options: 10000
Employee id: 2, Options: 10000
Employee id: 3, Options: 5000
Employee id: 2, Options: 10000
Employee id: 3, Options: 7500
Employee id: 3, Options: 7500
Employee id: 4, Options: 1500
Employee id: 101, Options: 2
The average of the employee options is: 5722.66666666667
Rattz_789-3.book Page 180 Tuesday, October 16, 2007 2:21 PM
CHAPTER 5 ■ NONDEFERRED OPERATORS
181
Aggregate
The Aggregate operator performs a user-specified function on each element of an input sequence,
passing in the function’s return value from the previous element and returning the return value of
the last element.

Prototypes
There are two prototypes I cover.
The First Aggregate Prototype
public static T Aggregate<T>(
this IEnumerable<T> source,
Func<T, T, T> func);
In this version of the prototype, the Aggregate operator enumerates through each element of the
input source sequence, calling the func method delegate on each, passing the return value from the
previous element as the first argument, and the element itself as the second argument, and finally
storing the value returned by func into an internal accumulator, which will then be passed to the next
element. The first element will be passed itself as the input value to the func method delegate.
The second prototype of the Aggregate operator behaves like the first version, except a seed value is
provided that will be the input value for the first invocation of the func method delegate instead of
the first element.
The Second Aggregate Prototype
public static U Aggregate<T, U>(
this IEnumerable<T> source,
U seed,
Func<U, T, U> func);
Exceptions
ArgumentNullException is thrown if the source or func argument is null.
InvalidOperationException is thrown if the input source sequence is empty, only for the first
Aggregate prototype, where no seed value is provided.
Examples
I will begin with an example of the first prototype, shown in Listing 5-63. In the example, I calculate
the factorial for the number 5. A factorial is the product of all positive integers less than or equal to
some number. The factorial of 5 is the product of all positive integers less than or equal to 5. So, 5!,
pronounced 5 factorial, will be equal to 1 * 2 * 3 * 4 * 5. It looks like I could use the Range operator and
the Aggregate operator to calculate this.
Listing 5-63. An Example of the First Aggregate Prototype

int N = 5;
IEnumerable<int> intSequence = Enumerable.Range(1, N);
// I will just output the sequence so all can see it.
foreach (int item in intSequence)
Console.WriteLine(item);
Rattz_789-3.book Page 181 Tuesday, October 16, 2007 2:21 PM
182
CHAPTER 5
■ NONDEFERRED OPERATORS
// Now calculate the factorial and display it.
// av == aggregated value, e == element
int agg = intSequence.Aggregate((av, e) => av * e);
Console.WriteLine("{0}! = {1}", N, agg);
In the previous code, I generate a sequence containing the integers from 1 to 5 using the Range
operator. After displaying each element in the generated sequence, I call the Aggregate operator
passing a lambda expression that multiplies the passed aggregated value with the passed element
itself. The following are the results:
1
2
3
4
5
5! = 120
■Caution You should be careful when using this version of the Aggregate operator that the first element
doesn’t get operated on twice, since it is passed in as the input value and the element for the first element. In the
previous example, my first call to my func lambda expression would have passed in 1 and 1. Since I just multiplied
these two values, and they are both ones, there is no bad side effect. But if I had added the two values, I would have
a sum that included the first element twice.
For the second prototype’s example, shown in Listing 5-64, I roll my own version of the Sum operator.
Listing 5-64. An Example of the Second Aggregate Prototype

IEnumerable<int> intSequence = Enumerable.Range(1, 10);
// I'll just output the sequence so all can see it.
foreach (int item in intSequence)
Console.WriteLine(item);
Console.WriteLine(" ");
// Now calculate the sum and display it.
int sum = intSequence.Aggregate(0, (s, i) => s + i);
Console.WriteLine(sum);
Notice that I passed 0 as the seed for this call to the Aggregate operator. And the envelope please:
1
2
3
4
5
6
7
8
9
10

55
Rattz_789-3.book Page 182 Tuesday, October 16, 2007 2:21 PM
CHAPTER 5 ■ NONDEFERRED OPERATORS
183
As you can see, I got the exact same results that I did when calling the Sum operator in Listing 5-51.
Summary
Wow, my head is spinning. I hope I didn’t lose too many of you so far. I know a lot of this and the
previous chapter is a little dry, but these two chapters are packed with the essentials of LINQ. I hope
that as I covered each query operator you tried to visualize when you might use it. A large part of
making LINQ effective for you is having a feel for the operators and what they do. Even if you can’t

remember every variation of each operator, just knowing they exist and what they can do for you is
essential.
From my coverage of LINQ to Objects and the Standard Query Operators, hopefully you can see
just how powerful and convenient LINQ is for querying data of all types of in-memory data collections.
With nearly 50 operators to choose from, LINQ to Objects is sure to make your data-querying
code more consistent, more reliable, and more expedient to write.
I can’t point out enough that most of the Standard Query Operators work on collections that
implement the IEnumerable<T> interface, and this excludes the legacy C# collections. I know sure as
can be that some readers are going to miss this fact and get frustrated because they have legacy code
with an ArrayList and cannot seem to find a way to query data from it. If this is you, please read
about the Cast and OfType operators.
Now that you hopefully have a sound understanding of LINQ to Objects and just what LINQ can
do for you, it’s time to learn about using LINQ to query and generate XML. This functionality is called
LINQ to XML and, not so coincidentally, that is the name of the next part of this book.
Rattz_789-3.book Page 183 Tuesday, October 16, 2007 2:21 PM
Rattz_789-3.book Page 184 Tuesday, October 16, 2007 2:21 PM

×