.NET: Доступ к непубличным членам из динамической сборки

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

18
задан Community 23 May 2017 в 11:44
поделиться