April 2006 - Posts
I've got to try thisI've been occasionally peering in at the NDoc project on source forge, and I've not seen it updated for .NET 2.0. But, a search showed this page:
http://jonas.lagerblad.com/blog/?cat=2
Downloading and trying it out.
Generics and patternsOne of my concerns with most of the articles on generics is that we seem to concentrate on collections, collections, and more collections. But, generics are good for other items as well. So, I wrote the following article discussing how you can implement a couple of common design patterns using generics
The online articleImplementing Patterns with Generics
Hey, Hey, HockeytownI realize this is a tech blog, but come on, it's the Stanley Cup Playoffs. (which were gone last year, and that's just not right)
Anyway, to honor the return of hockeytown, the Stanley Cup Finals, and Mo' Cheese, here are my first round picks (with entirely subjective justifications)
Western:
Detroit Red Wings vs. Edmonton Oilers
Red Wings in 5. (hey, this is hockeytown)
Dallas Stars vs. Colorado Avalanche
Stars in 4. There are three reasons for this. I grew up in Minnesota, so I have a soft spot for the North Star franchise. Mike Modano grew up in Michigan, and I've played golf with his dad. And, I'd pick any team to beat the Colorado Avalanche. (Claude the Turtle, Patrick Roy, etc)
Calgary Flames vs. Anaheim Mighty Ducks
Calgary in 5. Igilna is one of the best hockey players around, and they are playing a team that took their name from a pathetic Disney movie.
Nashville Predators vs. San Jose Sharks
Umm, Who cares? Either one would lose to the wings in the next round
Eastern:
Ottawa Senators vs. Tampa Bay Lightning
Ottawa in 5. Canada vs. Florida. 'nuff said.
Carolina Hurricanes vs. Montreal Canadiens
Montreal in 6. Canada (and original 6) vs. tobacco road. This ain't basketball.
New Jersey Devils vs. New York Rangers
Rangers in 7 (original 6 again, but no really good reason)
Buffalo Sabres vs. Philadelphia Flyers
Buffalo in 5. Buffalo has Slava Koslav (former Red Wing), and Philadelphia is, well, Philadelpia. It was easy.
Conversations: caching collectionsThis will be a shorter than most of my LINQ blogs. Today, I’ll quickly point out that LINQ adds a few new ways to perform conversions. These new conversions revolve around var, anonymous types, and collections of unrelated objects.
In addition to some syntactic modifications, these conversions change the runtime behavior. Many of the LINQ methods and queries don’t create collections, but instead return the next item only when requested. The conversion operators create the collection for you, so you can have the entire set of objects at once.
The simplest conversion operator is ToArray(), which should be familiar:
double[] doubles = { 1.7, 2.3, 1.9, 4.1, 2.9 };
var sortedDoubles =
from d in doubles
orderby d descending
select d;
var doublesArray = sortedDoubles.ToArray();This version of ToArray() is an extension method that works on any type that implements IEnumerable<T>. It also makes use of an internal class, Buffer<T>, which makes some more sophisticated choices about how to build an array from any enumerable type.
If you want a richer collection, consider the ToList() or ToDictionary() extension methods:
string[] words = { "cherry", "apple", "blueberry" };
var sortedWords =
from w in words
orderby w
select w;
var wordList = sortedWords.ToList();var scoreRecords = new [] { new {Name = "Alice", Score = 50},
new {Name = "Bob" , Score = 40},
new {Name = "Cathy", Score = 45}
};var scoreRecordsDict = scoreRecords.ToDictionary(sr => sr.Name);
The ToDictionary() method takes an expression that evaluates the key. This expression defines the Name as the key to the dictionary. There is another versions of the ToDictionary() method that takes another parameter so you can specify the key and the value for the dictionary.
Finally, there is the OfType() extension method that you use to extract all the members of a collection that are the target type, or a type derived from the target type.
object[] numbers = { null, 1.0, "two", 3, "four", 5, "six", 7.0 };
var doubles = numbers.OfType<double>();The important lesson here is that the conversion methods return the entire collection, instead of an object that can enumerate the collection. In addition, the different conversion methods let you initialize the collection type you want with the results of your LINQ queries.
Next, we’ll move on to the Element queries and more.
Part 1The general Query Syntax
Part 2The one where I discuss Object and Collection Initializers
Part 3The one where I finish restriction operators
Part 4Beginning to discuss projections
Part 5Anonymous types and projections
Part 6Discussing indexed, filtered, and compound queries
Part 7Finishing up the projection items
Part 8Projection operators and extension methods
Part 9OrderBy, ThenBy, and Descending, Oh my
Part 10Grouping operators, and building nested groups
Part 11Set Operations, You bet.
And I'll be at The Learning Center, answering questions on developer toolsTech Ed is coming to Boston in June.

I recently got word that I've been invited to help at 'The Learning Center' at Tech Ed Boston.
I actually prefer the learning center to giving a canned talk. It's more fun for me to help folks with their current challenges. It's great to help someone by giving them information they need today, as opposed to pointing them toward something they should learn one of these days.
It's also more challenging: You can't prepare, because there's no script. You can only share the knowledge you already have.
I don't have my schedule for TLC yet, I'll post an update when I finalize that.
I'm speaking in Dayton on April 26Effective C#, Part 1 and 2
Writing correct and maintainable programs quickly should be the most important goal for everyone writing software. The problem is that there is no silver bullet, no quick fix to just generate great software so it gets glossed over and lost is the shuffle of getting to production quicker. However, there are techniques that make it easier to create maintainable, extensible, correct programs, and this seminar will focus on applying those techniques using the C# language. While discussing these best practices, we’ll examine the tools in Visual Studio.NET that support creating world class software. We’ll close the session by examining the changes and additions in the most recent version of C# and Visual Studio that will make it easier to use the proper techniques.
The Dayton OH .NET User Group Home pageEverything you wanted to know about the group
Set operations? You bet.Often, when you run queries, you’ll find that your results contain duplicates, or you create queries using multiple sources, and want to find the shared, or distinct objects in the different result sets. LINQ provides a variety of set operators to do perform standard set operations on your query results, or any arbitrary collections.
So, let’s look at the catalog of set operators for LINQ:
Distinct:
Distinct() is another extension method, which removes duplicates from a set:
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source) {
Dictionary<T, object> dict = new Dictionary<T, object>();
foreach (T element in source) {
if (!dict.ContainsKey(element)) {
dict.Add(element, null);
yield return element;
}
}
}There are two samples in the 101 samples app that show Distinct. First, retrieving the unique prime factors of a number:
int[] factorsOf300 = { 2, 2, 3, 5, 5 };
var uniqueFactors = factorsOf300.Distinct();Second, retrieving all the distinct product categories from a list of products.
List<Product> products = GetProductList();
var categoryNames = (
from p in products
select p.Category)
.Distinct();
I’m less than thrilled with this second sample, because in a real application, the list of categories would be another table, and a simple query should retrieve all the categories without the extra work to find distinct categories from another table. But, that’s another story.
Union:
Of course, taking the union of two different sets is useful, and the standard query operators include a Union extension method:
public static IEnumerable<T> Union<T>(this IEnumerable<T> first,
IEnumerable<T> second) {
Dictionary<T, object> dict = new Dictionary<T, object>();
foreach (T element in first) {
if (!dict.ContainsKey(element)) {
dict.Add(element, null);
yield return element;
}
}
foreach (T element in second) {
if (!dict.ContainsKey(element)) {
dict.Add(element, null);
yield return element;
}
}
}
Union, like Distinct, is fairly simple. You can use it to create a set of numbers from two different sources:
int[] numbersB = { 1, 3, 5, 7, 8 };
var uniqueNumbers = numbersA.Union(numbersB);Or, to build a list of the first letters from different sets (in this case, customers and products):
List<Product> products = GetProductList();
List<Customer> customers = GetCustomerList();
var productFirstChars =
from p in products
select p.ProductName[0];
var customerFirstChars =
from c in customers
select c.CompanyName[0];
var uniqueFirstChars =
productFirstChars.Union(customerFirstChars);
Notice that in both cases, the Union method essentially performs a Distinct(): Shared elements found in both collections are only returned once.
Intersect:
Of course, once you’ve got the union of two sets, you may as well add the intersection of two sets. The answer is (surprise) another extension method:
public static IEnumerable<T> Intersect<T>(this IEnumerable<T> first,
IEnumerable<T> second) {
Dictionary<T, object> dict = new Dictionary<T, object>();
foreach (T element in first) dict[element] = null;
foreach (T element in second) {
if (dict.ContainsKey(element)) dict[element] = dict;
}
foreach (KeyValuePair<T, object> pair in dict) {
if (pair.Value != null) yield return pair.Key;
}
}
Like before, the 101 samples gives two quick examples of how to use this. First, creating the intersection of two arrays of numbers:
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
var commonNumbers = numbersA.Intersect(numbersB);Then, let’s play weird games with the product and customer lists to create a list of all the first letters shared by product names and customer names:
List<Product> products = GetProductList();
List<Customer> customers = GetCustomerList();
var productFirstChars =
from p in products
select p.ProductName[0];
var customerFirstChars =
from c in customers
select c.CompanyName[0];
var commonFirstChars = productFirstChars.Intersect(customerFirstChars);
Except:
Next on the ever exciting list of set operations is Except, which returns those values found in set 1, but not in set 2:
Except is another extension method that uses in internal dictionary to create the set of values found in the first collection, but not the second. Like the examples above, you use Except the same way:
int[] numbersA = { 0, 2, 4, 5, 6, 8, 9 };
int[] numbersB = { 1, 3, 5, 7, 8 };
IEnumerable<int> aOnlyNumbers = numbersA.Except(numbersB);List<Product> products = GetProductList();
List<Customer> customers = GetCustomerList();
var productFirstChars =
from p in products
select p.ProductName[0];
var customerFirstChars =
from c in customers
select c.CompanyName[0];
var productOnlyFirstChars = productFirstChars.Except(customerFirstChars);
Come back next time for conversions.
Part 1The general Query Syntax
Part 2The one where I discuss Object and Collection Initializers
Part 3The one where I finish restriction Operators
Part 4Beginning to discuss projections
Part 5Anonymous types and projections
Part 6Discussing indexed, filtered, and compound queries
Part 7Finishing up the projection items
Part 8Projection operators and extension methods
Part 9OrderBy, ThenBy, and Descending. Oh my
Part 10Grouping operators, and building nested groups
May 13th, 2006 at Washtenaw Community CollegeDay of .NET is a one-day conference on all things .NET organized by developers for developers. This event is being offered at no cost to anyone interested in .NET development, and features speakers from across the Heartland Region, as well a special guest speaker: Mark Miller from Developer Express and Mondays.
The Day of .NET in Ann Arbor is a collaborative effort between the following INETA member groups:
This rare event takes place Saturday, May 13, 2006 on the campus of Washtenaw Community College (Business Education Building) in Ann
Arbor, Michigan from 9:00 am to 5:15 pm.
Those of you in the Ann Arbor Area will know several of the speakers: Josh Holmes, Martin Shoemaker, Drew Robbins, Paul Kimmel ...
And, I'll be speaking about LINQ (who'd a thunk it?)
Further details and event registration at: http://dayofdotnet.org
Grouping operators, and building nested groupsSo, we’ve covered the ordering operations, next comes grouping. The LINQ Grouping operators enable you to sub-divide the results of your queries based on any property of the objects returned. You can use this functionality for subtotals, to arrange objects in categories, or to provide other calculations based on sub-groups of objects.
The grouping operators perform their actions by using the capabilities of anonymous types to produce the groupings, and a generic class to store the group. These samples will show you some of the interesting things you can build with the new features in C# 3.0. Implementing grouping does not need any features that I haven’t blogged about before, but uses them to build some new classes that you haven’t seen.
To begin, let’s look at the first grouping sample in its entirety:
public void Linq40() {
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 }; var numberGroups =
from n in numbers
group n by n % 5 into g
select new {Remainder = g.Key, Numbers = g.Group};
foreach (var g in numberGroups) {
Console.WriteLine(
"Numbers with a remainder of {0} when divided by 5:",
g.Remainder);
foreach (var n in g.Numbers) {
Console.WriteLine(n);
}
}
}
The output shows different collections for each possible remainder:
Numbers with a remainder of 0 when divided by 5:
5
0
Numbers with a remainder of 4 when divided by 5:
4
9
Numbers with a remainder of 1 when divided by 5:
1
6
Numbers with a remainder of 3 when divided by 5:
3
8
Numbers with a remainder of 2 when divided by 5:
7
2
There is one new aspect to this query, this line of code:
group n by n % 5 into g
That calls the GroupBy extension method, so the whole query could be written like this:
numbers.GroupBy( n => n % 5).Select
(g => new {Remainder = g.Key, Numbers = g.Group});
The GroupBy method is simply another extension method defined in Sequence.cs. There are four versions that return a sequence of groups. The sequence is a dictionary that contains Key / Group elements. The Key is the item that determines the group membership (in the case above, that’s the remainder). The Group is a list of all the elements that match the key.
The sequence is an instance of another generic class defined in sequence.cs: The Grouping<K, T> class.
Other simple groups can be formed to create lists of words that start with the same letter:
string[] words = { "blueberry", "chimpanzee", "abacus",
"banana", "apple", "cheese" };
var wordGroups =
from w in words
group w by w[0] into g
select new {FirstLetter = g.Key, Words = g.Group};Or, for a closer to real life example, products that are part of the same category:
List<Product> products = GetProductList();
var orderGroups =
from p in products
group p by p.Category into g
select new {Category = g.Key, Products = g.Group};
Like everything else I’ve discussed so far in the LINQ code, these are the small building blocks that can build larger more complicated queries. For example, the following query builds a list of orders grouped by customer, sub-grouped by year, and then sub-grouped by month.
public void Linq43() {
List<Customer> customers = GetCustomerList(); var customerOrderGroups = from c in customers
select
new {c.CompanyName,
YearGroups =
from o in c.Orders
group o by o.OrderDate.Year into yg
select
new {Year = yg.Key,
MonthGroups =
from o in yg.Group
group o by o.OrderDate.Month into mg
select new {Month = mg.Key, Orders = mg.Group}
}
};
ObjectDumper.Write(customerOrderGroups, 3);
}
A section of the output looks like this:
CompanyName=Alfreds Futterkiste YearGroups=...
YearGroups: Year=1997 MonthGroups=...
MonthGroups: Month=8 Orders=...
Orders: OrderID=10643 OrderDate=8/25/1997 Total=814.50
MonthGroups: Month=10 Orders=...
Orders: OrderID=10692 OrderDate=10/3/1997 Total=878.00
Orders: OrderID=10702 OrderDate=10/13/1997 Total=330.00
YearGroups: Year=1998 MonthGroups=...
MonthGroups: Month=1 Orders=...
Orders: OrderID=10835 OrderDate=1/15/1998 Total=845.80
MonthGroups: Month=3 Orders=...
Walk through this a bit, and you’ll see it’s not really so hard.
from c in customers // Iterate every customer.
select // Select something from the customer.
new {c.CompanyName, // Get the customer name
YearGroups = // Create a new group object
from o in c.Orders // From the orders
group o by o.OrderDate.Year into yg // yg is the year group
select // The group is the output of another select
new {Year = yg.Key, // The key is the year .
MonthGroups = // The list is a list of groups.
from o in yg.Group // Taken from a year’s worth of orders.
group o by o.OrderDate.Month into mg // The group is named mg.
// The key is the month, the orders are the list.
select new {Month = mg.Key, Orders = mg.Group}
}
};
The last two samples I'll discuss today show that you can form groups based on some calculated property of the items in your list. The sample shows how to create groups from anagrams of different words. There are two different points here. The first is that the key is the word, trimmed of all blanks. Second, the group is formed by the equality comparer defined in the AnagramEqualityComparer class. The AnagramEqualityComparer considers two strings equal if they contain the same letters.
public void Linq44() {
string[] anagrams = {"from ", " salt", " earn ",
" last ", " near ", " form "};
var orderGroups = anagrams.GroupBy(w => w.Trim(), new
AnagramEqualityComparer()); ObjectDumper.Write(orderGroups, 1);
}
public class AnagramEqualityComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y) {
return getCanonicalString(x) == getCanonicalString(y);
}
public int GetHashCode(string obj) {
return getCanonicalString(obj).GetHashCode();
}
private string getCanonicalString(string word) {
char[] wordChars = word.ToCharArray();
Array.Sort<char>(wordChars);
return new string(wordChars);
}
}The output is shown below:
Key=from Group=...
Group: from
Group: form
Key=salt Group=...
Group: salt
Group: last
Key=earn Group=...
Group: earn
Group: near
And, of course, there’s nothing magical about those operations. The next sample shows that you can create a new object to use as the contents of the list. In this version, string is converted to upper case before being added to the list:
string[] anagrams = {"from ", " salt", " earn ",
" last ", " near ", " form "};
var orderGroups = anagrams.GroupBy(w => w.Trim(), a => a.ToUpper(),
new AnagramEqualityComparer());The output is below:
Key=from Group=...
Group: FROM
Group: FORM
Key=salt Group=...
Group: SALT
Group: LAST
Key=earn Group=...
Group: EARN
Group: NEAR
Next, I’ll discuss the set operators, which help you manage the contents of queries.
Part 1The general query syntax
Part 2The one where I discuss Object and Collection initializers
Part 3The one where I finish restriction operators
Part 4Beginning to discuss projections
Part 5Anonymous types and projections
Part 6Discussing indexed, filtered, and compound queries
Part 7Finishing up the projection items
Part 8Projection Operators and Extension methods
Part 9OrderBy, ThenBy, and Descending. Oh my