.NET에서 런타임에 새 코드를 컴파일하고 실행할 수 있습니까?
-
04-07-2019 - |
문제
참고 : 수학적 표현 평가는이 질문의 초점이 아닙니다. .NET에서 런타임에 새 코드를 컴파일하고 실행하고 싶습니다. 그 말 ...
사용자가 다음과 같은 방정식을 텍스트 상자에 입력 할 수 있도록하고 싶습니다.
x = x / 2 * 0.07914
x = x^2 / 5
그리고 해당 방정식이 들어오는 데이터 포인트에 적용됩니다. 들어오는 데이터 포인트는 다음으로 표시됩니다 엑스 각 데이터 포인트는 사용자 지정 방정식으로 처리됩니다. 나는 올해 전에했지만 모든 계산에 대한 방정식의 텍스트를 구문 분석해야했기 때문에 솔루션이 마음에 들지 않았습니다.
float ApplyEquation (string equation, float dataPoint)
{
// parse the equation string and figure out how to do the math
// lots of messy code here...
}
데이터 포인트의 보트로드를 처리 할 때는 약간의 오버 헤드가 소개됩니다. 방정식을 한 번만 구문 분석해야 할 수 있도록 방정식을 즉시 함수로 변환 할 수 있기를 원합니다. 다음과 같이 보일 것입니다.
FunctionPointer foo = ConvertEquationToCode(equation);
....
x = foo(x); // I could then apply the equation to my incoming data like this
함수 convertequationTocode는 방정식을 구문 분석하고 적절한 수학을 적용하는 함수에 대한 포인터를 반환합니다.
앱은 기본적으로 실행 시간에 새 코드를 작성하는 것입니다. .NET에서 가능합니까?
해결책
예! 에서 발견 된 방법을 사용합니다 Microsoft.csharp, System.codedom.compiler, 그리고 시스템 반사 이름 공간. 다음은 하나의 메소드 ( "add42")로 클래스 ( "someclass")를 컴파일 한 다음 해당 메소드를 호출 할 수있는 간단한 콘솔 앱입니다. 이것은 코드 디스플레이에 스크롤 막대가 나타나는 것을 방지하기 위해 포맷 한 베어 본 예입니다. 런타임에 새 코드를 컴파일하고 사용하는 것을 보여주는 것입니다.
using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Reflection;
namespace RuntimeCompilationTest {
class Program
{
static void Main(string[] args) {
string sourceCode = @"
public class SomeClass {
public int Add42 (int parameter) {
return parameter += 42;
}
}";
var compParms = new CompilerParameters{
GenerateExecutable = false,
GenerateInMemory = true
};
var csProvider = new CSharpCodeProvider();
CompilerResults compilerResults =
csProvider.CompileAssemblyFromSource(compParms, sourceCode);
object typeInstance =
compilerResults.CompiledAssembly.CreateInstance("SomeClass");
MethodInfo mi = typeInstance.GetType().GetMethod("Add42");
int methodOutput =
(int)mi.Invoke(typeInstance, new object[] { 1 });
Console.WriteLine(methodOutput);
Console.ReadLine();
}
}
}
다른 팁
당신은 이것을 시도 할 수 있습니다 : calculator.net
수학 표현을 평가합니다.
게시물에서 다음을 지원합니다.
MathEvaluator eval = new MathEvaluator();
//basic math
double result = eval.Evaluate("(2 + 1) * (1 + 2)");
//calling a function
result = eval.Evaluate("sqrt(4)");
//evaluate trigonometric
result = eval.Evaluate("cos(pi * 45 / 180.0)");
//convert inches to feet
result = eval.Evaluate("12 [in->ft]");
//use variable
result = eval.Evaluate("answer * 10");
//add variable
eval.Variables.Add("x", 10);
result = eval.Evaluate("x * 10");
페이지 다운로드BSD 라이센스에 따라 배포됩니다.
예, 사용자 유형 C#을 텍스트 상자에 넣은 다음 해당 코드를 컴파일하고 앱 내에서 실행할 수 있습니다. 우리는 맞춤형 비즈니스 로직을 허용하기 위해 작업에서 그렇게합니다.
다음은 기사를 시작해야합니다.
빈 공급 "더미"XML 스트림에서 system.xml.xpath.xpathnavigator를 만들 수 있으며 XPath 평가자를 사용하여 표현식을 평가할 수도 있습니다.
static object Evaluate ( string xp )
{
return _nav.Evaluate ( xp );
}
static readonly System.Xml.XPath.XPathNavigator _nav
= new System.Xml.XPath.XPathDocument (
new StringReader ( "<r/>" ) ).CreateNavigator ( );
이 표현식 내에서 사용할 변수를 등록하려면 xpathnodeiterator를 사용하는 평가 오버로드를 전달할 수있는 XML을 동적으로 빌드 할 수 있습니다.
<context>
<x>2.151</x>
<y>231.2</y>
</context>
그런 다음 "x / 2 * 0.07914"와 같은 표현식을 쓸 수 있으며 X는 XML 컨텍스트에서 노드 값입니다. 또 다른 좋은 점은 수학 및 문자열 조작 방법 및 더 많은 것들이 포함 된 모든 XPath 코어 함수에 액세스 할 수 있다는 것입니다.
더 나아가려면 확장 기능 및 변수에 대한 참조를 해결할 수있는 자신의 XSLTCustomContext (또는 주문형 게시물)를 구축 할 수도 있습니다.
object result = Evaluate ( "my:func(234) * $myvar" );
내 : func는 c#/. net 메소드에 매핑되어 매개 변수로 이중 또는 int를 취합니다. Myvar는 XSLT 컨텍스트 내에서 변수로 등록됩니다.
Codedom 또는 Lambda Expression Trees를 볼 수 있습니다. 나는 그 중 하나가 당신이 이것을 달성 할 수 있어야한다고 생각합니다. 표현 나무는 아마도 더 좋은 방법 일뿐 만 아니라 학습 곡선이 더 높습니다.
보일러 플레이트 클래스를 만들어 CSSHARPCODEPROVIDER를 사용 하여이 작업을 수행했습니다. 그런 다음 사용자 코드를 보일러 플레이트에 삽입하고 컴파일합니다.
이 접근 방식의 위험은 방정식을 입력하는 사용자가 응용 프로그램에 따라 보안 문제가 될 수있는 모든 것을 입력 할 수 있다는 것입니다.
보안이 전혀 우려되는 경우 Lambda Expression Tree를 사용하는 것이 좋습니다. 그러나 그렇지 않은 경우 Csharpcodeprovider를 사용하는 것은 상당히 강력한 옵션입니다.
당신은 시작할 수 있습니다 여기 그리고 당신이 정말로 그것에 들어가고 싶다면, 우우 귀하의 요구를 충족시키기 위해 수정할 수 있습니다. 당신은 또한 통합 할 수 있습니다 .NET가있는 lua. 이 중 세 가지가 귀하의 대의원의 본문 내에서 사용될 수 있습니다. ConvertEquationToCode
.
당신은 본 적이 있습니다 http://ncalc.codeplex.com ?
확장 가능하고 빠르며 (예 : 자체 캐시가 있음) EvaluateFunction/EvaluateParameter 이벤트를 처리하여 실행 시간에 사용자 정의 기능 및 계장을 제공 할 수 있습니다. 예제 표현식이 구문 분석 할 수 있습니다.
Expression e = new Expression("Round(Pow(Pi, 2) + Pow([Pi2], 2) + X, 2)");
e.Parameters["Pi2"] = new Expression("Pi * Pi");
e.Parameters["X"] = 10;
e.EvaluateParameter += delegate(string name, ParameterArgs args)
{
if (name == "Pi")
args.Result = 3.14;
};
Debug.Assert(117.07 == e.Evaluate());
또한 유니 코드 및 많은 데이터 유형을 기본적으로 처리합니다. 그레이머를 변경하려면 뿔 파일이 함께 제공됩니다. 새로운 기능을로드하기 위해 MEF를 지원하는 포크도 있습니다.
vici.parser를 시도하십시오 : 여기에서 다운로드 (무료) , 지금까지 찾은 가장 유연한 표현 파서/평가자입니다.
다른 모든 것이 실패하면 System.reflection.emit 네임 스페이스 아래에 클래스가 있습니다.
당신이 사용할 수있는 system.CodeDom
코드를 생성하고 즉시 컴파일하려면 살펴보십시오. 여기
당신은 구현할 수 있습니다 포스트 픽스 스택 계산기. 기본적으로해야 할 일은 표현식을 postfix 표기법으로 변환 한 다음 PostFix의 토큰을 반복하여 계산하는 것입니다.
간단한 표현을위한보다 현대적인 라이브러리 : System.linq.dynamic.core. .NET Standard/.NET Core와 호환되며 Nuget을 통해 사용할 수 있으며 소스를 사용할 수 있습니다.
https://system-linq-dynamic-core.azurewebsites.net/html/de47654c-7ae4-9302-3061-a630706cb8.htm https://github.com/stefh/system.linq.dynamic.core https://www.nuget.org/packages/system.linq.dynamic.core/
이것은 매우 가볍고 역동적 인 라이브러리입니다.
이 라이브러리에 대한 간단한 래퍼 클래스를 썼습니다.
string sExpression = "(a == 0) ? 5 : 10";
ExpressionEvaluator<int> exec = new ExpressionEvaluator<int>(sExpression);
exec.AddParameter("a", 0);
int n0 = exec.Invoke();
표현식이 컴파일되면 매개 변수 값을 업데이트하고 표현식을 다시 침입 할 수 있습니다.
코드를 작성하지 않고 해당 문자열에있는 특수 문자를 기반으로 문자열의 일부에 기본 연산자를 적용하는 재귀 함수를 수행합니다. 하나 이상의 특수 문자가 발견되면 문자열을 분해 하고이 두 부분으로 호출합니다.
당신의 구현이 가능한지 모르겠습니다. ConvertEquationToCode
그러나 함수는 수행해야 할 계산을 나타내는 데이터 구조를 생성 할 수 있습니다.
예를 들어, 리프 노드가 계산의 입력을 나타내는 트리를 만들 수 있으며, 잎이 아닌 노드가 중간 결과를 나타내고 루트 노드가 전체 계산을 나타냅니다.
몇 가지 장점이 있습니다. 예를 들어, What-IF 분석을 수행하고 한 번에 하나의 입력 값을 변경하려는 경우 변경 한 값에 따라 달라지는 결과를 다시 계산하면서 그렇지 않은 결과를 유지할 수 있습니다.