Pergunta

Nota: avaliação da expressão matemática não é o foco desta questão. Eu quero compilar e executar o novo código em tempo de execução em .NET. Dito isto ...

Eu gostaria de permitir que o usuário digite qualquer equação, como o seguinte, numa caixa de texto:

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

E tem essa equação aplicada aos pontos de dados de entrada. Os pontos de dados de entrada são representadas por x e cada ponto de dados é processada pela equação especificada pelo utilizador. Eu fiz isso há alguns anos, mas não o fiz como a solução porque exigia a análise do texto da equação para cada cálculo:

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

Quando você está processando carradas de pontos de dados, isto introduz um pouco de sobrecarga. Eu gostaria de ser capaz de traduzir a equação para uma função, em tempo real, de modo que ele só tem de ser analisado uma vez. Seria algo parecido com isto:

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

Função ConvertEquationToCode iria analisar a equação e retornar um ponteiro para uma função que se aplica a matemática adequada.

O aplicativo seria basicamente escrever novo código em tempo de execução. Isso é possível com .NET?

Foi útil?

Solução

Sim! Usando métodos encontrada no Microsoft.CSharp , System.CodeDom.Compiler, e System.Reflection nome espaços. Aqui é um aplicativo de console simples que compila uma classe ( "SomeClass") com um método ( "Add42") e, em seguida, permite que você chamar esse método. Este é um exemplo de esqueleto que eu formatado para baixo para evitar as barras de rolagem apareçam na exibição do código. É apenas para demonstrar a compilação e usando o novo código em tempo de execução.

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

Outras dicas

Você pode tentar isso: Calculator.Net

Ele irá avaliar uma expressão matemática.

A partir da postagem que vai apoiar o seguinte:

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

Página de download E é distribuído sob a licença BSD.

Sim, definitivamente possível ter o tipo de usuário C # numa caixa de texto, em seguida, compilar esse código e executá-lo de dentro de seu aplicativo. Fazemos isso no meu trabalho para permitir a lógica de negócios personalizada.

Aqui está um artigo (eu não tenho mais do que desnatado-lo), que deve começar:

http://www.c-sharpcorner.com/UploadFile/ ChrisBlake / RunTimeCompiler12052005045037AM / RunTimeCompiler.aspx

Você também pode criar um System.Xml.XPath.XPathNavigator de um "manequim" fluxo XML vazio, e avaliar expressões usando o avaliador 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 ( );

Se você quiser registrar variáveis ??para uso dentro desta expressão, você pode dinamicamente XML compilação que você pode passar a sobrecarga Avaliar que leva um XPathNodeIterator.

<context>
  <x>2.151</x>
  <y>231.2</y>
</context>

Você pode então escrever expressões como "x / 2 * 0,07914" e, em seguida, x é o valor do nó no seu contexto XML. Outra coisa boa é, você terá acesso a todas as funções essenciais XPath, que inclui matemática e métodos de manipulação de corda, e mais coisas.

Se você quiser levá-lo ainda mais, você pode até mesmo construir seu próprio XsltCustomContext (ou mal postar aqui on demand) onde você pode resolver referências a extensão funções e variáveis:

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

minha: func é mapeado para um método C # / NET que leva um casal ou int como parâmetro.. myvar é registrada como uma variável dentro do contexto XSLT.

Você pode tentar olhar para nenhum CodeDom ou lambda Árvores de expressão. Eu acho que qualquer um daqueles deve permitir que você para fazer isso. Árvores de expressão são provavelmente a melhor maneira de ir, mas também têm uma curva de aprendizagem mais elevado.

Eu fiz isso usando CSharpCodeProvider criando a classe placa de caldeira e outras coisas função como uma string const dentro da minha classe gerador. Então eu inserir o código do usuário na placa de caldeira e de compilação.

Foi bastante simples de fazer, mas o perigo dessa abordagem é que o usuário entrar na equação poderia entrar apenas sobre qualquer coisa que poderia ser um problema de segurança, dependendo da aplicação.

Se a segurança é de todo uma preocupação, eu recomendaria usando Lambda Árvores de expressão, mas se não, usando CSharpCodeProvider é uma opção bastante robusto.

Você poderia começar aqui e se você realmente quer chegar a ele , Boo pode ser modificado para atender às suas necessidades. Você também pode integrar LUA com .NET . Qualquer três destes poderiam ser utilizados dentro do corpo de um delegado para seu ConvertEquationToCode.

Você viu http://ncalc.codeplex.com ?

É extensível, rápido (por exemplo, tem seu próprio cache) permite que você forneça funções personalizadas e varaibles em tempo de execução por manipulação de eventos EvaluateFunction / EvaluateParameter. expressões exemplo, pode analisar:

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

Ele também suporta Unicode e digite nativamente muitos dados. Ele vem com um arquivo de chifre se você quiser mudar a gramática. Há também uma bifurcação que suporta MEF para carregar novas funções.

Tente Vici.Parser: baixá-lo aqui (livre) , é o mais analisador de expressão flexível / avaliador que eu encontrei até agora.

Se tudo isso falhar, existem classes no namespace System.Reflection.Emit que você pode usar para produzir novas montagens, classes e métodos.

Você pode usar system.CodeDom para gerar o código e compilá-lo on the fly ter um olhar aqui

Você poderia implementar um postfix pilha da calculadora . Basicamente o que você tem a fazer é converter a expressão a notação postfix, e depois simplesmente iterar sobre as fichas em seu postfix de calcular.

Aqui uma biblioteca de mais moderno para expressões simples: System.Linq.Dynamic.Core. É compatível com .NET Standard / .NET Core, ele está disponível através NuGet, ea fonte está disponível.

https: // sistema -linq-dynamic-core.azurewebsites.net/html/de47654c-7ae4-9302-3061-ea6307706cb8.htm https://github.com/StefH/System.Linq.Dynamic.Core https://www.nuget.org/packages/System.Linq.Dynamic .Core /

Esta é uma biblioteca muito leve e dinâmica.

Eu escrevi uma classe de invólucro simples para esta biblioteca que vamos me fazer coisas como esta:

  string sExpression = "(a == 0) ? 5 : 10";
  ExpressionEvaluator<int> exec = new ExpressionEvaluator<int>(sExpression);
  exec.AddParameter("a", 0);
  int n0 = exec.Invoke();

Uma vez que a expressão é compilado, você pode simplesmente atualizar os valores dos parâmetros e re-invocar a expressão.

Gostaria de fazer uma função recursiva que faz código não escrita mas em vez disso se aplica operadores básicos para partes de uma string com base em caracteres especiais encontrados no essa cadeia. Se mais de um caractere especial é encontrado, ele rompe a corda e chama-se sobre essas duas partes.

Eu não sei se é possível implementar a sua função ConvertEquationToCode, no entanto, você pode gerar uma estrutura de dados que representa o cálculo que você precisa executar.

Por exemplo, você poderia construir uma árvore cujos nós folhas representam a entrada para o seu cálculo, cujos nós não-folha representam resultados intermediários, e cujo nó raiz representa todo o cálculo.

Ele tem algumas vantagens. Por exemplo, se você está fazendo análises hipotéticas e deseja alterar o valor de uma entrada de cada vez, você pode recalcular os resultados que dependem do valor que você alterou, mantendo os resultados que não.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top