EditChapter 2 - Introducing LINQ to Objects
EditLanguage Features
EditListing 2-1 : This example demonstrates adding a GetSHA1Hash method to the String type as an example extension method
This example demonstrates adding a GetSHA1Hash method to the String type as an example extension method.
public void Listing_2_1_ExtensionMethods()
{
// SHA1 Hashing a string.
// GetSHA1Hash is introduced via extension method
string password = "ClearTextPassword";
string hashedPassword = password.GetSHA1Hash();
// write the results to the Console window
Console.WriteLine("– SHA1 Hashing a string –");
Console.WriteLine("Original: " + password);
Console.WriteLine("Hashed: " + hashedPassword);
}
public static class MyStringExtensions
{
// extension method added to the String type,
// with no additional arguments
public static string GetSHA1Hash(
this string text)
{
if (string.IsNullOrEmpty(text))
return null;
SHA1Managed sha1 = new SHA1Managed();
byte[] bytes = sha1.ComputeHash(
new UnicodeEncoding().GetBytes(text));
return Convert.ToBase64String(bytes);
}
// extension method added to the String type,
// single string argument: url.
public static string CreateHyperlink(
this string text,
string url)
{
return String.Format(
"<a href='{0}'>{1}</a>", url, text);
}
}
Console output (Execution time: 2ms):
[
Hide/Show]
– SHA1 Hashing a string –
Original: ClearTextPassword
Hashed: DVuwKeBX7bqPMDefYLOGLiNVYmM=
Top
EditListing 2 : Extension Methods
This sample demonstrates how to add Extension Methods to various types.
public void Listing_2_ExtensionMethods()
{
// creating a hyperlink HTML snippet
// CreateHyperlink introduced via extension method
string name = "Hooked on LINQ";
string link = name.CreateHyperlink(
"http://www.hookedonlinq.com");
Console.WriteLine("– String to hyperlink –");
Console.WriteLine("Original: " + name);
Console.WriteLine("Hyperlink text: " + link);
Console.WriteLine();
}
public static class MyStringExtensions
{
// extension method added to the String type,
// with no additional arguments
public static string GetSHA1Hash(
this string text)
{
if (string.IsNullOrEmpty(text))
return null;
SHA1Managed sha1 = new SHA1Managed();
byte[] bytes = sha1.ComputeHash(
new UnicodeEncoding().GetBytes(text));
return Convert.ToBase64String(bytes);
}
// extension method added to the String type,
// single string argument: url.
public static string CreateHyperlink(
this string text,
string url)
{
return String.Format(
"<a href='{0}'>{1}</a>", url, text);
}
}
Console output (Execution time: 0ms):
[
Hide/Show]
– String to hyperlink –
Original: Hooked on LINQ
Hyperlink text: <a href='http://www.hookedonlinq.com'>Hooked on LINQ</a>
Top
EditListing 2-2 : Object initializer syntax - before and after
This sample demonstrates the before and after syntax changes of Object Initializers.
public void Listing_2_2_ObjectInitializers()
{
// old initialization syntax => multiple statements
Contact contactOld = new Contact();
contactOld.LastName = "Magennis";
contactOld.DateOfBirth = new DateTime(1973, 12, 09);
// new initialization syntax => single statement
Contact contactNew = new Contact
{
LastName = "Magennis",
DateOfBirth = new DateTime(1973, 12, 09)
};
}
public class Contact
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public DateTime DateOfBirth { get; set; }
public string State { get; set; }
public static List<Contact> SampleData()
{
return new List<Contact> {
new Contact {FirstName = "Barney", LastName = "Gottshall", DateOfBirth = new DateTime(1945,10,19), Phone = "885 983 8858", Email = "bgottshall@aspiring–technology.com", State = "CA" },
new Contact {FirstName = "Armando", LastName = "Valdes", DateOfBirth = new DateTime(1973,12,09), Phone = "848 553 8487", Email = "val1@aspiring–technology.com", State = "WA" },
new Contact {FirstName = "Adam", LastName = "Gauwain", DateOfBirth = new DateTime(1959,10,03), Phone = "115 999 1154", Email = "adamg@aspiring–technology.com", State = "AK" },
new Contact {FirstName = "Jeffery", LastName = "Deane", DateOfBirth = new DateTime(1950,12,16), Phone = "677 602 6774", Email = "jeff.deane@aspiring–technology.com", State = "CA" },
new Contact {FirstName = "Collin", LastName = "Zeeman", DateOfBirth = new DateTime(1935,02,10), Phone = "603 303 6030", Email = "czeeman@aspiring–technology.com", State = "FL" },
new Contact {FirstName = "Stewart", LastName = "Kagel", DateOfBirth = new DateTime(1950,02,20), Phone = "546 607 5462", Email = "kagels@aspiring–technology.com", State = "WA" },
new Contact {FirstName = "Chance", LastName = "Lard", DateOfBirth = new DateTime(1951,10,21), Phone = "278 918 2789", Email = "lard@aspiring–technology.com", State = "WA" },
new Contact {FirstName = "Blaine", LastName = "Reifsteck", DateOfBirth = new DateTime(1946,05,18), Phone = "715 920 7157", Email = "blaine@aspiring–technology.com", State = "TX" },
new Contact {FirstName = "Mack", LastName = "Kamph", DateOfBirth = new DateTime(1977,09,17), Phone = "364 202 3644", Email = "mack.kamph@aspiring–technology.com", State = "TX" },
new Contact {FirstName = "Ariel", LastName = "Hazelgrove", DateOfBirth = new DateTime(1922,05,23), Phone = "165 737 1656", Email = "arielh@aspiring–technology.com", State = "OR" }
};
}
}
Top
EditListing 2-3 :Collection Initialization syntax - before and after
This sample demonstrates the before and after syntax changes of Collection Initializers.
public void Listing_2_3_CollectionInitializers()
{
// old initialization syntax => multiple statements
List<string> stringsOld = new List<string>();
stringsOld.Add("string 1");
stringsOld.Add("string 2");
// new initialization syntax => single statement
List<string> stringsNew = new List<string> {
"string 1",
"string 2" };
// combining object and collection initialization
// create a list of contacts and add two records.
List<Contact> list = new List<Contact> {
new Contact {
LastName = "Magennis",
DateOfBirth = new DateTime(1973,12,09)
},
new Contact {
LastName = "Doherty",
DateOfBirth = new DateTime(1978,1,05)
}
};
}
public class Contact
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public DateTime DateOfBirth { get; set; }
public string State { get; set; }
public static List<Contact> SampleData()
{
return new List<Contact> {
new Contact {FirstName = "Barney", LastName = "Gottshall", DateOfBirth = new DateTime(1945,10,19), Phone = "885 983 8858", Email = "bgottshall@aspiring–technology.com", State = "CA" },
new Contact {FirstName = "Armando", LastName = "Valdes", DateOfBirth = new DateTime(1973,12,09), Phone = "848 553 8487", Email = "val1@aspiring–technology.com", State = "WA" },
new Contact {FirstName = "Adam", LastName = "Gauwain", DateOfBirth = new DateTime(1959,10,03), Phone = "115 999 1154", Email = "adamg@aspiring–technology.com", State = "AK" },
new Contact {FirstName = "Jeffery", LastName = "Deane", DateOfBirth = new DateTime(1950,12,16), Phone = "677 602 6774", Email = "jeff.deane@aspiring–technology.com", State = "CA" },
new Contact {FirstName = "Collin", LastName = "Zeeman", DateOfBirth = new DateTime(1935,02,10), Phone = "603 303 6030", Email = "czeeman@aspiring–technology.com", State = "FL" },
new Contact {FirstName = "Stewart", LastName = "Kagel", DateOfBirth = new DateTime(1950,02,20), Phone = "546 607 5462", Email = "kagels@aspiring–technology.com", State = "WA" },
new Contact {FirstName = "Chance", LastName = "Lard", DateOfBirth = new DateTime(1951,10,21), Phone = "278 918 2789", Email = "lard@aspiring–technology.com", State = "WA" },
new Contact {FirstName = "Blaine", LastName = "Reifsteck", DateOfBirth = new DateTime(1946,05,18), Phone = "715 920 7157", Email = "blaine@aspiring–technology.com", State = "TX" },
new Contact {FirstName = "Mack", LastName = "Kamph", DateOfBirth = new DateTime(1977,09,17), Phone = "364 202 3644", Email = "mack.kamph@aspiring–technology.com", State = "TX" },
new Contact {FirstName = "Ariel", LastName = "Hazelgrove", DateOfBirth = new DateTime(1922,05,23), Phone = "165 737 1656", Email = "arielh@aspiring–technology.com", State = "OR" }
};
}
}
Top
EditListing 2-4 : Local variable declaration, implicitly typed examples
This sample demonstrates Implicitly typed local variables.
public void Listing_2_4_ImplicitlyTypedLocalVariables()
{
// implicitly typed local variable declarations
var anInt = 1;
var aString = "Testing";
var listContact = new List<Contact>();
var intArray = new int[] { 0, 1, 2, 3, 4 };
// the above are identical to the following declarations
int anIntOld = 1;
string aStringOld = "Testing";
List<Contact> listContactOld = new List<Contact>();
int[] intArrayOld = new int[] { 0, 1, 2, 3, 4 };
// list is defined as type: List<Contact>,
// it shows how object and collection
// initialization work with the var style init.
var list = new List<Contact> {
new Contact {
LastName = "Magennis",
DateOfBirth = new DateTime(1973,12,09)
},
new Contact {
LastName = "Doherty",
DateOfBirth = new DateTime(1978,1,05)
}
};
/* The following declarations won't compile:
(courtesy of the C# 3.0 Language Specification)
var x; // no initializer to infer type from
var z = null; // null does not have a type
var u =
delegate { return 1; }; // anon. function has no type
var v = v++; // initializer cannot refer to itself
var y = {1, 2, 3}; // array initializer not permitted
*/
// just to remove compiler warnings.
anInt = anIntOld;
aString = aStringOld;
}
public class Contact
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public DateTime DateOfBirth { get; set; }
public string State { get; set; }
public static List<Contact> SampleData()
{
return new List<Contact> {
new Contact {FirstName = "Barney", LastName = "Gottshall", DateOfBirth = new DateTime(1945,10,19), Phone = "885 983 8858", Email = "bgottshall@aspiring–technology.com", State = "CA" },
new Contact {FirstName = "Armando", LastName = "Valdes", DateOfBirth = new DateTime(1973,12,09), Phone = "848 553 8487", Email = "val1@aspiring–technology.com", State = "WA" },
new Contact {FirstName = "Adam", LastName = "Gauwain", DateOfBirth = new DateTime(1959,10,03), Phone = "115 999 1154", Email = "adamg@aspiring–technology.com", State = "AK" },
new Contact {FirstName = "Jeffery", LastName = "Deane", DateOfBirth = new DateTime(1950,12,16), Phone = "677 602 6774", Email = "jeff.deane@aspiring–technology.com", State = "CA" },
new Contact {FirstName = "Collin", LastName = "Zeeman", DateOfBirth = new DateTime(1935,02,10), Phone = "603 303 6030", Email = "czeeman@aspiring–technology.com", State = "FL" },
new Contact {FirstName = "Stewart", LastName = "Kagel", DateOfBirth = new DateTime(1950,02,20), Phone = "546 607 5462", Email = "kagels@aspiring–technology.com", State = "WA" },
new Contact {FirstName = "Chance", LastName = "Lard", DateOfBirth = new DateTime(1951,10,21), Phone = "278 918 2789", Email = "lard@aspiring–technology.com", State = "WA" },
new Contact {FirstName = "Blaine", LastName = "Reifsteck", DateOfBirth = new DateTime(1946,05,18), Phone = "715 920 7157", Email = "blaine@aspiring–technology.com", State = "TX" },
new Contact {FirstName = "Mack", LastName = "Kamph", DateOfBirth = new DateTime(1977,09,17), Phone = "364 202 3644", Email = "mack.kamph@aspiring–technology.com", State = "TX" },
new Contact {FirstName = "Ariel", LastName = "Hazelgrove", DateOfBirth = new DateTime(1922,05,23), Phone = "165 737 1656", Email = "arielh@aspiring–technology.com", State = "OR" }
};
}
}
Top
EditListing 2-5 : Declaring and using Anonymous Types
This sample demonstrates Anonymous Types.
public void Listing_2_5_AnonymousTypes()
{
// simple anonymous type declaration
Console.WriteLine("– Simple Anonymous Type –");
var item = new { Name = "Car", Price = 9989.00 };
Console.WriteLine("Type: {0}, Name: {1}, Price: {2}",
item.GetType().ToString(), item.Name, item.Price);
// declaring and working with array of anonymous types
Console.WriteLine();
Console.WriteLine("– Iterating Anonymous Types Array –");
var list = new[] {
new { LastName = "Magennis",
DateOfBirth = new DateTime(1973,12,09)
},
new { LastName = "Doherty",
DateOfBirth = new DateTime(1978,1,05)
}
};
foreach (var x in list)
Console.WriteLine("{0} ({1})",
x.LastName, x.DateOfBirth);
// compiler optomization – from the C# specification:
// within the same program, two anonymous object
// initializers that specify a sequence of properties of
// the same names and compile–time types in the same order
// will produce instances of the same anonymous type.
var p1 = new { Name = "Lawnmower", Price = 495.00 };
var p2 = new { Name = "Shovel", Price = 26.95 };
p1 = p2; // valid: the same anonymous type
}
Console output (Execution time: 3ms):
[
Hide/Show]
– Simple Anonymous Type –
Type: <>f__AnonymousType15`2[System.String,System.Double], Name: Car, Price: 9989
– Iterating Anonymous Types Array –
Magennis (12/9/1973 12:00:00 AM)
Doherty (1/5/1978 12:00:00 AM)
Top
EditListing 2-6 : Anonymous method (C# 2.0) and lambda expression (C# 3.0) examples
This sample demonstrates Lambda Expressions and Anonymous Types.
public void Listing_2_6_LambdaExpressions()
{
// connecting code to a buttons click event
// anonymous method –
Button button = new Button();
button.Click += delegate(object sender, EventArgs args)
{
MessageBox.Show("Clicked");
};
// lambda expression –
button.Click += (object sender, EventArgs args) =>
MessageBox.Show("Clicked");
var data = Contact.SampleData().ToList();
// passing code to a ForEach method on a List<T>
// anonymous method –
data.ForEach(delegate(Contact c)
{ c.LastName = c.LastName.ToUpper(); });
// lambda expression –
data.ForEach(c => c.LastName = c.LastName.ToUpper());
data.ForEach( c => Console.WriteLine("{0}, {1}",
c.LastName, c.FirstName) );
// passing code to an extension method
// anonymous method –
var q1 = data
.Where(
delegate(Contact c){return c.State == "WA";});
// lambda expression –
var q2 = data
.Where(c => c.State == "WA");
}
Console output (Execution time: 7ms):
[
Hide/Show]
GOTTSHALL, Barney
VALDES, Armando
GAUWAIN, Adam
DEANE, Jeffery
ZEEMAN, Collin
KAGEL, Stewart
LARD, Chance
REIFSTECK, Blaine
KAMPH, Mack
HAZELGROVE, Ariel
Top
EditListing 2-7 : Query Expressions
This sample demonstrates Query Expressions and how the language enhancement meld into the LINQ story..
public void Listing_2_7_QueryExpressions()
{
// note: Person.SampleData() returns a populated
// List<Person> sample data collection.
// LINQ Query Expression Syntax
var query1 = from c in Person.SampleData()
where c.State == "WA"
select new
{
Name = c.FirstName + " " + c.LastName,
State = c.State
};
// LINQ Extension Method Syntax, identical to above
var query2 = Person.SampleData()
.Where(c => c.State == "WA")
.Select(c => new
{
Name = c.FirstName + " " + c.LastName,
State = c.State
});
foreach (var item in query1)
Console.WriteLine("{0}, ({1})", item.Name, item.State);
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string State { get; set; }
public static List<Person> SampleData()
{
// note: this sample data uses the Collection Initializer C#3.0
// language construct for simplicity.
return new List<Person> {
new Person { FirstName = "Troy", LastName = "Magennis", State = "WA" },
new Person { FirstName = "Janet", LastName = "Doherty", State = "MA" },
new Person { FirstName = "James", LastName = "Wann", State = "CA" },
new Person { FirstName = "Tara", LastName = "Wann", State = "WA" }
};
}
}
Console output (Execution time: 7ms):
[
Hide/Show]
Troy Magennis, (WA)
Tara Wann, (WA)
Top
EditLINQ to Objects Five Minute Overview
EditListing 2-8 : Simple LINQ Query over an array of integers
This sample demonstrates a simple LINQ query over an integer array.
public void Listing_2_8_SimpleQueryExpression()
{
int[] nums = new int[] { 0, 4, 2, 6, 3, 8, 3, 1 };
var result = from n in nums
where n < 5
orderby n
select n;
foreach (int i in result)
Console.WriteLine(i);
}
Console output (Execution time: 24ms):
[
Hide/Show]
Top
EditListing 2-9 : Simple LINQ that calculates the sum of all values in an integer array
This sample demonstrates a simple LINQ aggregation operator query that sums the values in an integer array.
public void Listing_2_9_SimpleAggregationQueryExpression()
{
int[] nums = new int[] { 0, 4, 2, 6, 3, 8, 3, 1 };
int result = nums.Sum();
Console.WriteLine(result);
}
Console output (Execution time: 0ms):
[
Hide/Show]
Top
EditListing 2-10 : Contacts who are less than 35 years of age
This sample demonstrates how to find all Contact less than 35 years of age, ordered from youngest to oldest.
public void Listing_2_10_ContactsLessThan35()
{
List<Contact> contacts = Contact.SampleData();
var q = from c in contacts
where c.DateOfBirth.AddYears(35) > DateTime.Now
orderby c.DateOfBirth descending
select string.Format("{0} {1} b.{2}",
c.FirstName,
c.LastName,
c.DateOfBirth.ToString("dd–MMM–yyyy")
);
foreach (string s in q)
Console.WriteLine(s);
}
Console output (Execution time: 11ms):
[
Hide/Show]
Top
EditListing 2-11 : Simple grouping based on a field value.
This sample demonstrates how to create sub-groups based on the value of an expression (all records matching that expression).
public void Listing_2_11_ContactGrouping()
{
List<Contact> contacts = Contact.SampleData();
var q = from c in contacts
group c by c.State;
foreach (var group in q)
{
Console.WriteLine("State: " + group.Key);
foreach (Contact c in group)
Console.WriteLine(" {0} {1}",
c.FirstName,
c.LastName);
}
}
Console output (Execution time: 4ms):
[
Hide/Show]
Top
EditListing 2-12 : Simple joining based on a shared value value.
This sample demonstrates how to join two in-memory collections based on a shared value.
public void Listing_2_12_JoiningData()
{
List<Contact> contacts = Contact.SampleData();
List<CallLog> callLog = CallLog.SampleData();
var q = from call in callLog
join contact in contacts on
call.Number equals contact.Phone
select new {
contact.FirstName,
contact.LastName,
call.When,
call.Duration
};
foreach (var c in q)
Console.WriteLine(
"{0} – {1} {2} ({3}min)",
c.When.ToString("ddMMM HH:m"), c.FirstName,
c.LastName, c.Duration);
}
Console output (Execution time: 14ms):
[
Hide/Show]
07Aug 08:12 – Barney Gottshall (2min)
07Aug 09:23 – Ariel Hazelgrove (15min)
07Aug 10:5 – Mack Kamph (1min)
07Aug 10:35 – Collin Zeeman (2min)
07Aug 11:15 – Stewart Kagel (4min)
07Aug 13:12 – Barney Gottshall (15min)
07Aug 13:47 – Barney Gottshall (3min)
07Aug 20:34 – Stewart Kagel (1min)
08Aug 10:10 – Stewart Kagel (3min)
08Aug 10:40 – Collin Zeeman (23min)
08Aug 14:0 – Armando Valdes (3min)
08Aug 14:37 – Armando Valdes (7min)
08Aug 15:23 – Chance Lard (6min)
08Aug 17:12 – Mack Kamph (20min)
12Jul 08:12 – Barney Gottshall (5min)
14Jun 09:23 – Ariel Hazelgrove (12min)
09Jul 10:5 – Mack Kamph (10min)
05Jul 10:35 – Collin Zeeman (22min)
07Jun 11:15 – Stewart Kagel (9min)
07Jun 13:12 – Barney Gottshall (10min)
07Jul 13:47 – Barney Gottshall (21min)
07Jul 20:34 – Stewart Kagel (7min)
08Jun 10:10 – Stewart Kagel (2min)
08Jun 10:40 – Collin Zeeman (3min)
08Jul 14:0 – Armando Valdes (32min)
08Jul 14:37 – Armando Valdes (13min)
08May 15:23 – Chance Lard (16min)
08Jun 17:12 – Mack Kamph (24min)
Top
EditListing 2-13 : Summarizing the data from two collections.
Incoming call log summary - shows filtering, ordering, grouping, joining and selection using aggregate values
public void Listing_2_13_SummarizingDataFromMultipleCollections()
{
List<Contact> contacts = Contact.SampleData();
List<CallLog> callLog = CallLog.SampleData();
var q = from call in callLog
where call.Incoming == true
group call by call.Number into g
join contact in contacts on
g.Key equals contact.Phone
orderby contact.FirstName, contact.LastName
select new {
contact.FirstName,
contact.LastName,
Count = g.Count(),
Avg = g.Average(c => c.Duration),
Total = g.Sum(c => c.Duration)
};
foreach (var call in q)
Console.WriteLine(
"{0} {1} – Calls:{2}, Time:{3}mins, Avg:{4}mins",
call.FirstName, call.LastName,
call.Count, call.Total, Math.Round(call.Avg, 2));
}
Console output (Execution time: 10ms):
[
Hide/Show]
Ariel Hazelgrove – Calls:2, Time:27mins, Avg:13.5mins
Armando Valdes – Calls:2, Time:20mins, Avg:10mins
Barney Gottshall – Calls:4, Time:31mins, Avg:7.75mins
Chance Lard – Calls:2, Time:22mins, Avg:11mins
Mack Kamph – Calls:2, Time:44mins, Avg:22mins
Stewart Kagel – Calls:2, Time:13mins, Avg:6.5mins
Top