.NET:从动态程序集访问非公共成员

| 我正在开发一个允许用户输入任意表达式的库。然后,我的库将这些表达式作为较大表达式的一部分编译为委托。现在,由于仍然未知的原因,有时/经常用ѭ0编译表达式会导致代码比如果不是编译表达式要慢得多。之前我问了一个问题,一种解决方法是不使用
Compile
,而是使用
CompileToMethod
并在新的动态程序集中的新类型上创建
static
方法。那行得通,代码很快。 但是用户可以输入任意表达式,结果表明,如果用户调用非公共函数或访问表达式中的非公共字段,则在委托为时会抛出“ 4”(对于非公共方法)。调用。 我在这里可能要做的就是创建一个新的
ExpressionVisitor
,该表达式检查表达式是否访问了非公共内容,并在这种情况下使用较慢的ѭ0but,但是我宁愿动态程序集以某种方式获得访问非公共内容的权利。公众成员。或者找出关于“ 0”变慢的方法(有时),我是否可以做些什么。 重现此问题的完整代码:
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;
    }
  }
}
    
已邀请:
问题不在于权限,因为没有权限可以使您无需反射即可访问非公共字段或另一个类的成员。这类似于您编译两个非动态程序集,而一个程序集在第二个程序集中调用公共方法的情况。然后,如果将方法更改为private而不重新编译第一个程序集,则第一个程序集调用现在将在运行时失败。换句话说,您的动态程序集中的表达式将被编译为一个普通的方法调用,即使在同一程序集中,它也没有从另一个类进行调用的权限。 由于没有权限可以解决您的问题,因此您可以将非公共字段和方法引用转换为使用反射的子表达式。 这是一个从您的测试案例中获取的示例。这将失败:
Expression<Func<int>> expression = () => 10 + GetValue();
但这将成功:
Expression<Func<int>> expression = () => 10 + (int)typeof(Program).GetMethod(\"GetValue\", BindingFlags.Static | BindingFlags.NonPublic).Invoke(null, null);
由于这不会导致异常崩溃,因此您可以看到您的动态程序集确实具有反射权限,并且可以访问私有方法,因此无法使用产生2的普通方法调用来执行此操作。     
我曾经有一个问题,使用DynamicMethod从生成的IL代码访问类的私有元素。 事实证明,类ѭ12the的构造函数有一个重载,它允许将类的类型接收到非常私有的访问中: http://msdn.microsoft.com/en-us/library/exczf7b9.aspx 该链接包含有关如何访问私有数据的示例...我知道这与表达式树无关,但它可能为您提供一些有关如何进行操作的线索。 编译表达式树时可能会有某种相似的事情……或者您可以将该表达式树创建为DynamicMethod。     
如果您创建了非动态程序集,则实际上可以为动态程序集添加一个
InternalsVisibleTo
(即使使用强名称也可以)。那将允许使用内部成员,您的情况就足够了? 为了获得一个想法,这是一个示例,该示例显示了如何使Moq的动态程序集能够使用其他程序集中的内部内容进行演示: http://blog.ashmind.com/2008/05/09/mocking-internal-interfaces-with-moq/ 如果这种方法还不够,我会结合使用Rick和Miguel的建议:为对非公共成员的每次调用创建\“ proxy \” DynamicMethods,并更改表达式树,以便使用它们而不是原始调用。     

要回复问题请先登录注册