I looked into the cool Dynamic List Sorting package on CodeProject. It's pretty good, but I wanted to get the absolute best performance for my framework, so I optimized the generated IL some [download here]. I've eliminated the local variable used to track the comparison- thus-far as it is always zero until we've got a mismatch. I've also added the ability to reference fields (as well as properties), and added flags to the DynamicMethod constructor to bypass accessiablity checks (allows access to private members).
This new version is very fast. In debug builds, property access is around 5-25% slower than field access, the cost of delegate invocation is about 15% and the cost of element-by-element versus using the object's ICompare method is 4%.
Here's the chart for sorting 500,000 Person objects (in seconds):
|Sort By||Field||Property||Cost of property||Cost of dynamic|
|Dynamic whole object||7.40||15.09%|
|Built-in whole object||6.43|
Sorting by "FirstName, lastName, Age" [property,field,property respectively] results in this generated IL (through the cool DebuggerVisualizer mentioned here)
IL_0000: ldarg.0 IL_0001: callvirt System.String get_FirstName()/DynamicComparerSample.Person IL_0006: ldarg.1 IL_0007: callvirt System.String get_FirstName()/DynamicComparerSample.Person IL_000c: callvirt Int32 CompareTo(System.String)/System.String IL_0011: dup IL_0012: brtrue.s IL_0046 IL_0014: pop IL_0015: ldarg.0 IL_0016: ldfld System.String lastName/DynamicComparerSample.Person IL_001b: ldarg.1 IL_001c: ldfld System.String lastName/DynamicComparerSample.Person IL_0021: callvirt Int32 CompareTo(System.String)/System.String IL_0026: dup IL_0027: brtrue.s IL_0046 IL_0029: pop IL_002a: ldarg.0 IL_002b: callvirt Double get_Age()/DynamicComparerSample.Person IL_0030: stloc V_0 IL_0034: nop IL_0035: nop IL_0036: ldloca.s V_0 IL_0038: nop IL_0039: nop IL_003a: nop IL_003b: ldarg.1 IL_003c: callvirt Double get_Age()/DynamicComparerSample.Person IL_0041: callvirt Int32 CompareTo(Double)/System.Double IL_0046: ret
Edit: I forgot the call to .Compare in the benchmark, which saves a LOT of time because then the object isn't wrapped in another delegate deep in the guts of the FCL. Numbers above have been updated.
UPDATE: Revised extensively to handle nulls and faster performance. See this.
UPDATE: Revised links to point to GooglePages so I'm not serving the files from my DSL.