よくある質問です
私は軽量な動的コンパイルを使用したいと思っています。Natashaはいくつかの十数メガバイトのメモリを事前にロードする必要があり、パッケージのサイズも増加すると聞きましたが、私にとっては重すぎると感じます。
答:Natashaのプレヒートは初心者向けであり、すべての準備作業を無視して直接動的コンパイルを行うことを意図しています。しかし、emitまたは式木の場合、動的コンパイルに必要なリフレクション関連のメタデータが提供される必要があります。emitおよび式木のプログラミング経験があれば、自分が書いた動的機能がどのようなメタデータに依存しているかを知ることができるはずですが、Natashaは事前ロードせずにカスタムのメタデータを追加することもできます。以下の例をご覧ください。この例では、入力 はvalueで、出力はMath.Floor(value/0.3)です。
emitバージョン
DynamicMethod dynamicMethod = new DynamicMethod("FloorDivMethod", typeof(double), new Type[] { typeof(double) }, typeof(Program).Module);
ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldc_R8, 0.3);
ilGenerator.Emit(OpCodes.Div);
ilGenerator.Emit(OpCodes.Call, typeof(Math).GetMethod("Floor", new Type[] { typeof(double) }));
ilGenerator.Emit(OpCodes.Ret);
Func<double, double> floorDivMethod = (Func<double, double>)dynamicMethod.CreateDelegate(typeof(Func<double, double>));
式木のバージョン
ParameterExpression valueParameter = Expression.Parameter(typeof(double), "value");
Expression divisionExpression = Expression.Divide(valueParameter, Expression.Constant(0.3));
Expression floorExpression = Expression.Call(typeof(Math), "Floor", null, divisionExpression);
Expression<Func<double, double>> expression = Expression.Lambda<Func<double, double>>(floorExpression, valueParameter);
Func<double, double> floorDivMethod = expression.Compile();
Natashaのバージョン
AssemblyCSharpBuilder builder = new();
var func = builder
.UseRandomLoadContext()
.UseSimpleMode()
.ConfigLoadContext(ctx => ctx
.AddReferenceAndUsingCode(typeof(Math))
.AddReferenceAndUsingCode(typeof(double)))
.Add("public static class A{ public static double Invoke(double value){ return Math.Floor(value/0.3); }}")
.GetAssembly()
.GetDelegateFromShortName<Func<double, double>>("A", "Invoke");
Natashaメソッドテンプレートラッパーバージョン
この拡張ライブラリ
DotNetCore.Natasha.CSharp.Extension.MethodCreator
は、元のNatashaを基にしており、Natasha v9.0以降で利用できます。
var simpleFunc = "return Math.Floor(arg1/0.3);"
.WithSimpleBuilder()
.WithMetadata(typeof(Math))
.ToFunc<double, double>();