LoginSignup
5

More than 5 years have passed since last update.

文字列のラムダ式をコンパイルしてC#で使えるようにする

Posted at

ラムダ式、便利ですよね。
文字列として、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;
            }
        }
    }


Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5