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