문제

참고 : 수학적 표현 평가는이 질문의 초점이 아닙니다. .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#을 텍스트 상자에 넣은 다음 해당 코드를 컴파일하고 앱 내에서 실행할 수 있습니다. 우리는 맞춤형 비즈니스 로직을 허용하기 위해 작업에서 그렇게합니다.

다음은 기사를 시작해야합니다.

http://www.c-sharpcorner.com/uploadfile/chrisblake/runtimecompiler12052005045037am/runtimecompiler.aspx

빈 공급 "더미"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 분석을 수행하고 한 번에 하나의 입력 값을 변경하려는 경우 변경 한 값에 따라 달라지는 결과를 다시 계산하면서 그렇지 않은 결과를 유지할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top