ユーザーが任意の式を入力できるようにするライブラリに取り組んでいます。私のライブラリは、これらの式をより大きな式の一部としてデリゲートにコンパイルします。現在、理由はまだ不明ですが、Compile
時々/頻繁に式をコンパイルすると、コンパイルされた式ではない場合よりもはるかに遅いコードになります。以前にこれについて質問しましたが、回避策の 1 つは を使用せず、新しい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;
}
}
}