我正在开发一个允许用户输入任意表达式的库。然后,我的库将这些表达式作为更大表达式的一部分编译到委托中。现在,由于仍然未知的原因,Compile
有时/经常编译表达式会导致代码比它不是编译表达式时慢得多。我之前问过一个关于这个的问题,一个解决方法是不使用Compile
,而是在新的动态程序集中的新类型上CompileToMethod
创建一个方法。static
这行得通,代码很快。
但是用户可以输入任意表达式,事实证明,如果用户调用非公共函数或访问表达式中的非公共字段,则System.MethodAccessException
在调用委托时会抛出一个(在非公共方法的情况下) .
我在这里可能做的是创建一个新ExpressionVisitor
的来检查表达式是否访问任何非公共的,并Compile
在这些情况下使用较慢的,但我宁愿让动态程序集以某种方式获得访问非公共成员的权利。或者找出我可以做些什么Compile
来变慢(有时)。
重现此问题的完整代码:
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;
}
}
}