ラムダ式、便利ですよね。
文字列として、TextBoxあたりから入力したラムダ式を実行したり、
XAMLの中にラムダ式を埋め込めると結構便利?かと思ってやってみました。
動的に文字列を組み立ててメタプログラミング!なんてこともできますね。
あまり早くなさそうなので、連発はやめたほうが良さそうですけどね。
使いまわすときは、キャッシュを効かせるといいと思います。
今どきなら、Roslynをつかってやるとかいうことになるのでしょうが、使っていません。
式ツリーも使っていません。よくわからなかった。
やり方的には力技という感じですね。
この記事はとても参考になりました。やや古いのですが。
C#をスクリプト言語として使う
filename
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Rawler.Tool.Script
{
public class ScriptUnitTest{
//使い方
public void Test()
{
var r = LambadLib.CompileLambda<int, int>("(n)=>n*n");
System.Console.WriteLine(r.Func(2));
}
}
public static class LambadLib
{
public struct LambadResult<T1, T2>
{
public CompilerError[] CompilerError { get; set; }
public Func<T1, T2> Func { get; set; }
}
public static LambadResult<T1, T2> CompileLambda<T1, T2>(string source)
{
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters cp = new CompilerParameters();
cp.GenerateInMemory = true;
cp.TreatWarningsAsErrors = false;
cp.ReferencedAssemblies.Add("System.dll"); // Regex
cp.ReferencedAssemblies.Add("System.Core.dll"); // Extensions
string source2 = @"
using System;
using System.Linq;
using System.Collections.Generic;
class FunctionClass{
Func<(T1), (T2)> test = (lambda);
public Func<(T1),(T2)> Test { get { return test; } }
}";
//入力したもので書き換え。
source2 = source2.Replace("(T1)",typeof(T1).Name).Replace("(T2)",typeof(T2).Name).Replace("(lambda)", source);
//コンパイル
CompilerResults cr = provider.CompileAssemblyFromSource(cp, source2);
LambadResult<T1, T2> r = new LambadResult<T1, T2>();
r.CompilerError = cr.Errors.OfType<CompilerError>().ToArray();
if (cr.Errors.Count > 0) return r;
//コンパイルしたアセンブリを取得
var asm = cr.CompiledAssembly;
//MainClassクラスのTypeを取得
Type t = asm.GetType("FunctionClass");
var instance = Activator.CreateInstance(t);
var m = t.GetMember("test");
var method = t.GetProperty("Test").GetValue(instance, null);
r.Func = (Func<T1, T2>)method;
return r;
}
}
}