私はユーザーが任意の式を入力できるようにするためのライブラリに取り組んでいます。私のライブラリは、より大きな表現の一部としてそれらの表現をデリゲートにコンパイルします。さて、まだ知られていない理由のために、Compile
で式をコンパイルすることは、コンパイルされた式ではない場合よりもはるかに低速なコードになります。 I asked a question about this以前の回避策は、Compile
ではなくCompileToMethod
を使用し、新しいダイナミックアセンブリの新しいタイプに対してstatic
メソッドを作成することでした。それは動作し、コードは高速です。.NET:動的アセンブリから非公開のメンバーにアクセスする
ユーザーは任意の式を入力できます。ユーザーが非公開関数を呼び出したり、式内の非公開フィールドにアクセスした場合は、System.MethodAccessException
(非公開メソッドの場合)がスローされます。デリゲートが呼び出されたとき。
私はおそらくここに何ができることは表現が何も非パブリックにアクセスし、それらの例にCompile
遅くを使用するかどうかを確認すること、新規ExpressionVisitor
を作成することですが、私はむしろ、動的アセンブリが何らかの形でアクセス権を取得していることがあるだろう非公開のメンバー。または、私ができることがあれば、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;
}
}
}
私はあなたに答えがありませんが、プライベートメソッドの呼び出しをサポートする必要があるのはなぜですか? – jlew
ユーザは可能であると予想しているため。 '()=> CallPrivateMethod()'のように、式を作成するときに*アクセス可能ですが、実行時には失敗します。彼がそれを実行し、それがクラッシュして燃えるまでは動作しないことを示すものは何もありません。それは本当に悪く、 "最小の驚き"のルールに違反しているので、私はそれを正当化することはできませんし、遅いコードを解決しなければなりません。 – JulianR
ユーザーがC#プログラマーである場合(たとえば、フォームに式を入力するのではなく)、意味があります。コンパイルされたデリゲートのリリース対デバッグモードをベンチマークしましたか?彼らはどのようにお互いを比較しているのですか? – jlew