using System; using System.Collections.Generic; using System.Query; using System.Diagnostics; // Simple class for test purposes. // Can't use an anonymous type, as we want to put it in a list class NameAndSize { int size; string name; public int Size { get { return size; } set { size = value; } } public string Name { get { return name; } set { name = value; } } } static class Extensions { public static V Max(this IEnumerable source, Func comparisonMap, Func selectMap) { int maxValue=0; V maxElement=default(V); bool gotAny = false; using (IEnumerator enumerator = source.GetEnumerator()) { while (enumerator.MoveNext()) { T sourceValue = enumerator.Current; int value = comparisonMap(sourceValue); if (!gotAny || value > maxValue) { maxValue = value; maxElement = selectMap(sourceValue); gotAny = true; } } } if (!gotAny) { throw new EmptySequenceException(); } return maxElement; } } class Test { delegate NameAndSize FindMaxDelegate(IList list); const int TestRuns = 5; const int ListSize = 1000000; static void Main(string[] args) { IList list = new List(); for (int i=0; i < ListSize; i++) { list.Add(new NameAndSize{Name="N"+i, Size=i}); } FindMaxDelegate[] tasks = new FindMaxDelegate[]{FindMaxByOrderBy, FindMaxByTwoQueries, FindMaxManually, FindMaxWithNewExtension }; TimeSpan[] times = new TimeSpan[tasks.Length]; for (int i=0; i < TestRuns; i++) { Console.WriteLine ("Running test series {0}", i); for (int j=0; j < tasks.Length; j++) { Stopwatch timer = Stopwatch.StartNew(); NameAndSize max = tasks[j](list); times[j] += timer.Elapsed; if (max != list[list.Count-1]) { throw new Exception ("Incorrect result!"); } } } Console.WriteLine ("Average times:"); for (int j=0; j < tasks.Length; j++) { Console.WriteLine ("{0}: {1}", tasks[j].GetInvocationList()[0].Method.Name, new TimeSpan(times[j].Ticks/TestRuns)); } } private static NameAndSize FindMaxByOrderBy(IList list) { return (from item in list orderby item.Size descending select item).First(); } private static NameAndSize FindMaxByEmbeddedWhere(IList list) { return (from item in list where item.Size==list.Max(x=>x.Size) select item).First(); } private static NameAndSize FindMaxByTwoQueries(IList list) { int maxSize = list.Max(x=>x.Size); return (from item in list where item.Size==maxSize select item).First(); } private static NameAndSize FindMaxManually(IList list) { // Note: this assumes the list is non-empty NameAndSize max = list[0]; foreach (NameAndSize item in list) { if (item.Size > max.Size) { max = item; } } return max; } private static NameAndSize FindMaxWithNewExtension(IList list) { return list.Max(x=>x.Size, x=>x); } }