본문 바로가기

C#/예제 코드

c# 의 Eval (동적 컴파일)

사전지식

c#에도 자바스크립트의 eval 같은 것이 있으나 그러한 작업은 태생적으로 느리다.


준비물 nuget.org

Install-Package Microsoft.CodeAnalysis.CSharp.Scripting -Version 4.0.1

OR

dotnet add package Microsoft.CodeAnalysis.CSharp.Scripting --version 4.0.1

실습

※ .net6.0 ( C#10.0 에서는 Main()을 생략한다 )

using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Scripting;
using System;


//기본편
var value = await CSharpScript.EvaluateAsync("1 + 1");
Console.WriteLine(value);


//응용편
ScriptState<object> state;
state = await CSharpScript.RunAsync("/*Hello script!*/",globals: new Global{x=1});
state = await state.ContinueWithAsync("int a = x ;");
state = await state.ContinueWithAsync("int b = 2;");
state = await state.ContinueWithAsync("int c = a + b;");
state = await state.ContinueWithAsync("var rtvalue = c;");
state = await state.ContinueWithAsync("rtvalue");
Console.WriteLine(state.ReturnValue);
public class Global { public int x; };

 

 

VS2022 console

 

 

참조

https://itnext.io/getting-start-with-roslyn-c-scripting-api-d2ea10338d2b

 

더보기

성능테스트

속도에 대한 테스트를 짤막하게 해 보았다.


-테스트 소스

using Microsoft.CodeAnalysis.CSharp.Scripting;
using System;
using System.Linq;
using System.Diagnostics;

 

var sw = Stopwatch.StartNew();

 

var testcase = new[] {
    "'Hello'",
    "'there~'" ,
    "'test'",
    "System.Math.Abs(1234)",
    "System.Math.Abs(5678)",
    "'bye~'",
}.Select(x => x.Replace("'","\""));

 

foreach(var str in testcase)
{
    sw.Restart();
    var obj = await CSharpScript.EvaluateAsync(str);
    sw.Stop();
    Console.WriteLine($"{str[^6..^0],-10} {obj,-10} {sw.ElapsedMilliseconds,4} ms");
}

-결과

VS2022 console

 


-분석

비동기 함수로 만들어져 있음에서 알 수 있듯이 첫 빠따가 굉장히 느리다.

그리고 같은 패턴의 내용이면 어느 정도 빨라진다.

그러므로 안 쓰던 메서드를 쓰면 더 느려진다.