Well, this question's pretty old now, and I'm waiting for a tf get
to complete... so I'll answer it myself.
Yes, LCG is dead in most cases.
We used to make quite a bit of use of LCG and it has now all been converted to use expression trees instead. They are much easier to build, the code is significantly easier to maintain and debug, and the error messages are generally more informative than 'Operation could destabilize the runtime' when you get things wrong during development.
But, perhaps most importantly, expression trees are composable in a way that Reflection.Emit is not. This means the architecture of the components used for runtime code generation can be more modular and even allow plugins to extend the code generation framework.
The one thing I've found that is supported by Reflection.Emit that isn't directly supported in expression trees is setting .initonly
fields. This, however, can be achieved by using a little helper class and invoking it in the expression tree, for example the one I used is below:
internal static class FieldHelper
{
public static TTarget AssignInitOnlyField<TTarget, TField>(
TTarget target, string fieldName, TField value)
{
var field = target.GetType().GetField(
fieldName,
BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic);
var boxed = (object)target; // required for value type support
field.SetValue(boxed, value);
return (TTarget)boxed;
}
}
It's worth mentioning the one down-side of using expression trees rather than LCG is that the construction and compilation of the expression trees is definitely slower than emitting the raw op-codes directly. Assuming you're caching the compiled methods this is unlikely to be a significant problem, but it's the one reason that could still compel you to use LCG.