Я работаю над библиотекой, которая позволяет пользователям вводить произвольные выражения. Затем моя библиотека компилирует эти выражения как часть большего выражения в делегат. Теперь, по неизвестным причинам, компиляция выражения с 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;
}
}
}