I'm working on a library that allows users to input arbitrary expressions. My library then compiles those expressions as part of a larger expression into a delegate. Now, for still unknown reasons compiling the expression with Compile
sometimes/often results in code that is far slower than it would be if it weren't a compiled expression. I asked a question about this before and one workaround was to not use Compile
, but CompileToMethod
and create a static
method on a new type in a new dynamic assembly. That works and the code is fast.
But users can input arbitrary expressions and it turns out that if the user calls a non-public function or accesses a non-public field in the expression, it throws a System.MethodAccessException
(in the case of a non-public method) when the delegate is invoked.
What I could probably do here is create a new ExpressionVisitor
that checks if the expression accesses anything non-public and use the slower Compile
in those cases, but I'd rather have that the dynamic assembly somehow gets the rights to access the non-public members. Or find out if there's anything I can do about Compile
being slower (sometimes).
The full code to reproduce this problem:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
namespace DynamicAssembly
{
public class Program
{
private static int GetValue()
{
return 1;
}
public static int GetValuePublic()
{
return 1;
}
public static int Foo;
static void Main(string[] args)
{
Expression<Func<int>> expression = () => 10 + GetValue();
Foo = expression.Compile()();
Console.WriteLine("This works, value: " + Foo);
Expression<Func<int>> expressionPublic = () => 10 + GetValuePublic();
var compiledDynamicAssemblyPublic = (Func<int>)CompileExpression(expressionPublic);
Foo = compiledDynamicAssemblyPublic();
Console.WriteLine("This works too, value: " + Foo);
var compiledDynamicAssemblyNonPublic = (Func<int>)CompileExpression(expression);
Console.WriteLine("This crashes");
Foo = compiledDynamicAssemblyNonPublic();
}
static Delegate CompileExpression(LambdaExpression expression)
{
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("MyAssembly"+ Guid.NewGuid().ToString("N")),
AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("Module");
var typeBuilder = moduleBuilder.DefineType("MyType", TypeAttributes.Public);
var methodBuilder = typeBuilder.DefineMethod("MyMethod",
MethodAttributes.Public | MethodAttributes.Static);
expression.CompileToMethod(methodBuilder);
var resultingType = typeBuilder.CreateType();
var function = Delegate.CreateDelegate(expression.Type,
resultingType.GetMethod("MyMethod"));
return function;
}
}
}