2008-10-24 2 views
33

참고 : 수식 표현 평가는이 질문의 초점이 아닙니다. .NET에서 런타임에 새 코드를 컴파일하고 실행하려고합니다. 말했다되고 그건 ... 나는 텍스트 상자에 다음과 같이 사용자가 어떤 식을 입력 할 수 있도록하고 싶습니다.NET에서 런타임시 새 코드를 컴파일하고 실행할 수 있습니까?

:

x = x/2 * 0.07914 
x = x^2/5 

들어오는 데이터 포인트에 적용하는 방정식이있다. 수신 데이터 포인트는 x으로 표시되며 각 데이터 포인트는 사용자 지정 방정식으로 처리됩니다. 나는이 년 전했지만이 모든 계산 방정식의 텍스트를 구문 분석이 필요하기 때문에이 솔루션을 좋아하지 않았다

float ApplyEquation (string equation, float dataPoint) 
{ 
    // parse the equation string and figure out how to do the math 
    // lots of messy code here... 
} 

당신이 데이터 포인트의 boatload에 처리를하고,이 꽤 소개 간접비. 방정식을 즉석에서 함수로 변환하여 한 번만 구문 분석 할 수 있기를 바랍니다. 그것은 다음과 같이 보일 것입니다 :

FunctionPointer foo = ConvertEquationToCode(equation); 
.... 
x = foo(x); // I could then apply the equation to my incoming data like this 

기능 ConvertEquationToCode 방정식을 분석하고 적절한 수학을 적용하는 함수에 대한 포인터를 반환합니다.

앱은 기본적으로 런타임에 새로운 코드를 작성합니다. .NET에서 가능합니까?

+0

가능한 복제 [I 동적으로 C#을 식을 계산할 수 있는가? (http://stackoverflow.com/questions/53844/how-can-i-evaluate-ac-sharp-expression-dynamically) – Ridkuma

답변

18

예! Microsoft.CSharp, System.CodeDom.CompilerSystem.Reflection 네임 스페이스에있는 메소드 사용 다음은 하나의 메소드 ("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(); 
     } 
    } 
} 
+0

이것은 간단한 산술 표현식에서는 매우 느립니다. –

+2

@JonathanNappee :이 작업을 수행하는 방법을 발견하게되어 기뻤으며, 훌륭하다고 말하지 않았습니다. 나는 당신의 성과 향상을보고 싶다! – raven

2

CodeDom 또는 Lambda Expression Trees를 살펴볼 수 있습니다. 나는 그 중 하나가 당신이 이것을 성취하도록 허용해야한다고 생각합니다. 표현식 트리가 더 좋은 방법이지만 학습 곡선도 커집니다.

-1

코드를 작성하지 않고 그 문자열에있는 특수 문자를 기반으로 문자열의 일부에 기본 연산자를 적용하는 재귀 함수를 사용합니다. 두 개 이상의 특수 문자가 발견되면 문자열을 분리하고 두 부분에서 자신을 호출합니다.

+0

당신이 원하는 것은 표현 파서입니다. 나는 한 번 식을 inix에서 postfix로 변환 한 다음 스택 기반의 posfix 파서를 사용하여이 작업을 수행했습니다. 이 두 가지 알고리즘은 웹 및 도서에 잘 정의되어 존재합니다. – Nick

2

here을 시작할 수 있으며 실제로 들어가려면 Boo을 필요에 맞게 수정할 수 있습니다. LUA with .NET을 통합 할 수도 있습니다. 이 중 3 개는 ConvertEquationToCode 대리인의 본문에 활용할 수 있습니다.

11

당신이 시도 할 수 있습니다 : 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"); 

Download Page 그리고 BSD 라이선스로 배포됩니다.

+2

CodeDom 네임 스페이스를 살펴보고 런타임에 코드를 컴파일 할 수 있습니다. – cfeduke

+0

이 라이브러리에는 몇 가지 버그가있는 것 같으며 여전히 지원되지 않는 것 같습니다. –

3

보일러 플레이트 클래스와 함수를 생성자 클래스 내 const 문자열로 생성하여 CSharpCodeProvider를 사용하여이 작업을 수행했습니다. 그런 다음 사용자 코드를 보일러 플레이트에 삽입하고 컴파일합니다.

이 방법의 위험성은 방정식을 입력하는 사용자가 응용 프로그램에 따라 보안 문제가 될 수있는 모든 것을 입력 할 수 있다는 점입니다.

보안 문제가있는 경우 람다 표현 트리를 사용하는 것이 좋지만 그렇지 않은 경우에는 CSharpCodeProvider를 사용하는 것이 매우 강력한 옵션입니다.

5

또한 빈, "더미"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 핵심 함수 에 액세스 할 수 있다는 것입니다.

object result = Evaluate ("my:func(234) * $myvar"); 

내 : FUNC가 당신이 그것을 더 먹고 싶어 경우 확장 함수와 변수에 대한 참조를 해결할 수있는

, 당신은 당신의 자신의 XsltCustomContext (또는 여기 수요에 병이 게시물) 을 구축 할 수 있습니다 매개 변수로 double 또는 int를 사용하는 C#/.NET 메서드에 매핑됩니다. myvar는 XSLT 컨텍스트 내에서 변수로 등록됩니다.

0

다른 모든 것이 실패하면 System.Reflection.Emit 네임 스페이스 아래에 새 어셈블리, 클래스 및 메서드를 만드는 데 사용할 수있는 클래스가 있습니다.

+0

하지만 한마디 한마디. 우리는 이것을 .Less (dotlesscss.com)에 사용했고 발광 코드는 대개 끔찍한 성능을 의미합니다. –

-2

ConvertEquationToCode 함수를 구현할 수 있는지는 잘 모르겠지만 수행해야하는 계산을 나타내는 데이터 구조를 생성 할 수 있습니다.

예를 들어 리프 노드가 계산을위한 입력을 나타내며 리프가 아닌 노드가 중간 결과를 나타내며 루트 노드가 전체 계산을 나타내는 트리를 작성할 수 있습니다.

몇 가지 장점이 있습니다. 예를 들어 what-if 분석을 수행하면서 한 번에 하나의 입력 값을 변경하려는 경우 변경하지 않은 결과는 그대로 유지하면서 변경 한 값에 따라 결과를 다시 계산할 수 있습니다.

1

Vici.Parser : download it here (free)을 사용해보세요. 지금까지 발견 한 가장 유연한 표현 파서/평가자입니다. 당신은 코드를 생성하고 즉시 에 컴파일 system.CodeDom을 사용할 수 있습니다

0

살펴에게 있습니다.기본적으로 표현식을 접미사 표기법으로 변환 한 다음 계산할 접미사의 토큰을 반복합니다.

3

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()); 

또한 유니 코드 & 많은 데이터가 기본적으로 입력 처리합니다. 문법을 바꾸려면 antler file이 함께 제공됩니다. 또한 새로운 기능을로드하기 위해 MEF를 지원하는 포크가 있습니다.

+0

왜 아래로 투표 ??? – GreyCloud

관련 문제