How can I inject a literal expression with Reflection.Emit?

I am working on a project to evaluate tokenized user expressions of varying complexity, using C # as a scripting language.

I have a working model using CodeDOM and reflection to create an evaluator class, create and load an assembly (GenerateInMemory = true), instantiate the class, and execute the evaluation method. However, I want to load the assembly into AppDomain so that I can unload it when the execution is complete. Studying this problem, I was turned to the AppDomain.DefineDynamicAssembly method. This is similar to what I need as I can create a collectible assembly.

Here are some examples of custom expressions and classes generated by my CodeDOM project:

Simple custom expression:

return Abs(@HDL@/@LDL@ * 5.5);

Generated Class:

namespace Lab.ResultProcessing
{

    public sealed class ExpressionEvaluator
    {
        public double Evaluate()
        {
            return System.Math.Abs(449.86881550861/74.934407754305 * 5.5);
        }
    }
}

A more complex user-defined expression:

double GFR;
double MA_GFR;
double MB_GFR;
double FA_GFR;
double FB_GFR;

GFR = (170 *
        Pow(@CREAT@, -0.999) *
        Pow(@YEARS@, -0.176) *
        Pow(@BUN@, -0.170) *
        Pow(@ALBUMIN@, 0.318));

MA_GFR = GFR;
MB_GFR = GFR * 1.180;
FA_GFR = GFR * 0.762;
FB_GFR = GFR * 1.180 * 0.762;

if (("@RACE@" != "B") && ("@GENDER@" == "M"))
{
    return MA_GFR;
}
else if (("@RACE@" == "B") && ("@GENDER@" == "M"))
{
    return MB_GFR;
}
else if (("@RACE@" != "B") && ("@GENDER@" == "F"))
{
    return FA_GFR;
}
else if (("@RACE@" == "B") && ("@GENDER@" == "F"))
{
    return FB_GFR;
}
else
{
    return GFR;
}

Generated Class:

namespace Lab.ResultProcessing
{

    public sealed class ExpressionEvaluator
    {
        public double Evaluate()
        {
            double GFR;
double MA_GFR;
double MB_GFR;
double FA_GFR;
double FB_GFR;

GFR = (170 *
        System.Math.Pow(0.797258181752292, -0.999) *     
        System.Math.Pow(63.6814545438073, -0.176) *
        System.Math.Pow(5.47258181752292, -0.170) *       
        System.Math.Pow(3.79725818175229, 0.318));    

MA_GFR = GFR;                                   
MB_GFR = GFR * 1.180;                           
FA_GFR = GFR * 0.762;                           
FB_GFR = GFR * 1.180 * 0.762;                   

if (("B" != "B") && ("M" == "M"))
{
    return MA_GFR;                              
}
else if (("B" == "B") && ("M" == "M"))
{
    return MB_GFR;                              
}
else if (("B" != "B") && ("M" == "F"))
{
    return FA_GFR;                              
}
else if (("B" == "B") && ("M" == "F"))
{
    return FB_GFR;                              
}
else
{
    return GFR;
}
;
        }
    }
}

Now I am trying to duplicate the functionality described above using Reflection.Emit. My problem is that I did not find a way to introduce a deokenizirovanny formula in the emitted class.

Here is the code I'm using:

public static object DynamicEvaluate2(string expression)
{
    AssemblyName assemblyName = new AssemblyName("Lab.ResultProcessing");
    AppDomain appDomain = AppDomain.CurrentDomain;
    AssemblyBuilder assemblyBuilder = appDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect);
    ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name);
    TypeBuilder typeBuilder = moduleBuilder.DefineType("ExpressionEvaluator", TypeAttributes.Sealed);
    MethodBuilder methodBuilder = typeBuilder.DefineMethod("Evaluate", MethodAttributes.Public | MethodAttributes.Final, typeof(double), null);
    ILGenerator methodGenerator = methodBuilder.GetILGenerator();

    methodGenerator.Emit(OpCodes.Ldobj, expression);
    methodGenerator.Emit(OpCodes.Ret);

    Type evaluatorType = typeBuilder.CreateType();
    MethodInfo methodInfo = evaluatorType.GetMethod("Evaluate");

    object evaluator = Activator.CreateInstance(evaluatorType);
    object result = methodInfo.Invoke(evaluator, null);

    return result;
}

When the methodInfo.Invoke method is called, I get the following error:

Test method ResultCalculatorTest.ResultCalculatorClassFactoryTest.DynamicEvaluate2Test throws an exception: System.Reflection.TargetInvocationException: The exception was thrown by the target of the call. ---> System.BadImageFormatException: token of bad classes.

So, I have a couple of questions:

Reflection.Emit?
# , IL?
?

.

+5
1
methodGenerator.Emit(OpCodes.Ldobj, expression);

, : ldobj Type, string. MSDN, ldobj , .

CodeDom, Reflection.Emit . expression IL- IL, . , .

Reflection.Emit - System.Linq.Expressions. , Reflection.Emit , CodeDom. , , .

+5

All Articles