Я работаю над библиотекой, которая позволяет пользователям вводить произвольные выражения. Затем моя библиотека компилирует эти выражения как часть более крупного выражения в делегат. Теперь, по еще неизвестным причинам, компиляция выражения с помощью 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> expression = () => 10 + GetValue();
Foo = expression.Compile()();
Console.WriteLine("This works, value: " + Foo);
Expression> expressionPublic = () => 10 + GetValuePublic();
var compiledDynamicAssemblyPublic = (Func)CompileExpression(expressionPublic);
Foo = compiledDynamicAssemblyPublic();
Console.WriteLine("This works too, value: " + Foo);
var compiledDynamicAssemblyNonPublic = (Func)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;
}
}
}