views:

90

answers:

1

According to Pro LINQ: Language Integrated Query in C# 2008, Prototype of OrderBy operator is

public static IOrderedEnumerable<T> OrderBy<T, K>(
    this IEnumerable<T> source,
    Func<T, K> keySelector)
where
    K : IComparable<K>

But the MSDN documentation does not have a generics contraint on TKey that it should be of type IComparable<TKey>

public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector
)

I am basically sorting Inventory by Unit and then by Size.

    var sortedInventories = inventories
                            .OrderBy(inventory => inventory.Unit)
                            .OrderBy(inventory => inventory.Size);

From the above code snippet, lambda expressions simply return inventory properties to sort by. It does not look like an expression that returns IComparer<T>

But according to logic, it looks like the lambda expression should be of type IComparer<T>.

Which one is the correct declaration of OrderBy?
(Apress.com Errata page has no information on it)

Here is a sample application I created to test OrderBy

public class Program
{
    public static void Main(string[] args)
    {
        var inventories = new[] {
            new Inventory { Unit = 1, Size = 2 },
            new Inventory { Unit = 2, Size = 4 },
            new Inventory { Unit = 3, Size = 6 },
        };
        var sortedInventories = inventories
                                .OrderBy(inventory => inventory.Unit)
                                .OrderBy(inventory => inventory.Size);

        foreach (var inventory in sortedInventories)
            Console.WriteLine("Unit: {0}; Size = {1}", inventory.Unit, inventory.Size);
    }
}

public class Inventory
{
    public int Unit { get; set; }
    public double Size { get; set; }
}
+3  A: 

Change your second "OrderBy" to "ThenBy". You're currently resorting everything, so it's effectively by Size and then Unit, but inefficiently. I'm not sure where you think IComparer<T> should come in, unless you specify it as another argument. Basically it uses Comparer<T>.Default unless you specify a separate comparer.

Anyway, your query should be:

var sortedInventories = inventories
                          .OrderBy(inventory => inventory.Unit)
                          .ThenBy(inventory => inventory.Size);

(With your test data you can't tell the difference, because in each case Size = Unit * 2. Try it with one item which has a small Unit and a large Size though.)

Yes, it looks like the book got the signature slightly wrong - possibly due to it changing shortly before release. If you were basically worried about getting the wrong results though, the above is the explanation.

Jon Skeet
Next section in the book deals with "ThenBy"... By the way, does this mean prototype of "OrderBy" (mentioned in the question) is not correct and I would have assume that MSDN document is the most current signature?
Sung Meister
Yes, generally go with MSDN - they usually get the signatures right at least.
Jon Skeet
Call we crazy, but I just use intellisense/object-browser/show-definition - nothing to get wrong then. Although of course MSDN is generated from code anyway (+Sandcastle?)
Marc Gravell
@Jon: Ouch, when I changed test data around, I was able to see the use of "ThenBy"
Sung Meister