UPDATE: This project is hosted on CodePlex as the Dynamic Reflection Library for all further updates.
RE: Dynamic sorting of objects using lightweight code generation.
I got a report of issues sorting objects that have null (not
Nullable<T>) values. In the previous implementation, I blindly call down to the CompareTo method associated with the property's
Type. This obviously doesn't work with virtual methods. For some types (like
String) it was enough to simply make the emitted code a
Call instead of a
CallVirt, but I didn't want to be half-right. So the new version does the right thing and handles the null-checks for the left and right filed/property values.
The emitted code is slightly more complex, but still about as fast as I now check for
IsFinal methods and use
Call instead of
CallVirt when possible. This optimization is in place for property get calls, and the call the CompareTo, so it is a bit faster.
I also fixed an issue if you compared a whole bunch of attributes and blew the generate IL so large that the loop-break label wasn't reachable by a short branch (nobody reported this, just noticed in code review).
The emitted code for "FirstName, lastName, Gender" [
Enum property, respectively] now looks like this:
IL_0000: ldarg.0 IL_0001: callvirt System.String get_FirstName()/DynamicComparerSample.Person IL_0006: dup IL_0007: brtrue.s IL_0018 IL_0009: pop IL_000a: ldarg.1 IL_000b: callvirt System.String get_FirstName()/DynamicComparerSample.Person IL_0010: brtrue.s IL_0015 IL_0012: ldc.i4.0 IL_0013: br.s IL_0023 IL_0015: ldc.i4.m1 IL_0016: br.s IL_0023 IL_0018: ldarg.1 IL_0019: callvirt System.String get_FirstName()/DynamicComparerSample.Person IL_001e: call Int32 CompareTo(System.String)/System.String IL_0023: dup IL_0024: brtrue IL_0060 IL_0029: pop IL_002a: ldarg.0 IL_002b: ldfld Double age/DynamicComparerSample.Person IL_0030: stloc.0 IL_0031: ldloca.s V_0 IL_0033: ldarg.1 IL_0034: ldfld Double age/DynamicComparerSample.Person IL_0039: call Int32 CompareTo(Double)/System.Double IL_003e: dup IL_003f: brtrue IL_0060 IL_0044: pop IL_0045: ldarg.0 IL_0046: callvirt DynamicComparerSample.Gender get_Gender()/DynamicComparerSample.Person IL_004b: box DynamicComparerSample.Gender IL_0050: ldarg.1 IL_0051: callvirt DynamicComparerSample.Gender get_Gender()/DynamicComparerSample.Person IL_0056: box DynamicComparerSample.Gender IL_005b: call Int32 CompareTo(System.Object)/System.Enum IL_0060: ret