Pergunta

Eu gostaria de fazer o equivalente a:

object result = Eval("1 + 3");
string now    = Eval("System.DateTime.Now().ToString()") as string

Seguindo Biri link, recebi este trecho (modificado para remover o método obsoleto ICodeCompiler.CreateCompiler():

private object Eval(string sExpression)
{
    CSharpCodeProvider c = new CSharpCodeProvider();
    CompilerParameters cp = new CompilerParameters();

    cp.ReferencedAssemblies.Add("system.dll");

    cp.CompilerOptions = "/t:library";
    cp.GenerateInMemory = true;

    StringBuilder sb = new StringBuilder("");
    sb.Append("using System;\n");

    sb.Append("namespace CSCodeEvaler{ \n");
    sb.Append("public class CSCodeEvaler{ \n");
    sb.Append("public object EvalCode(){\n");
    sb.Append("return " + sExpression + "; \n");
    sb.Append("} \n");
    sb.Append("} \n");
    sb.Append("}\n");

    CompilerResults cr = c.CompileAssemblyFromSource(cp, sb.ToString());
    if (cr.Errors.Count > 0)
    {
        throw new InvalidExpressionException(
            string.Format("Error ({0}) evaluating: {1}", 
            cr.Errors[0].ErrorText, sExpression));
    }

    System.Reflection.Assembly a = cr.CompiledAssembly;
    object o = a.CreateInstance("CSCodeEvaler.CSCodeEvaler");

    Type t = o.GetType();
    MethodInfo mi = t.GetMethod("EvalCode");

    object s = mi.Invoke(o, null);
    return s;

}  
Foi útil?

Solução

Usando compilar em tempo real, como este exemplo mostra.

Ou usando Fugir, que é exatamente pelo mesmo motivo.

Outras dicas

Eu escrevi um projeto de código aberto, Expresso Dinâmico, que pode converter expressões de texto escritas usando uma sintaxe C# em delegados (ou árvore de expressões).Expressões de texto são analisadas e transformadas em Árvores de Expressão sem usar compilação ou reflexão.

Você pode escrever algo como:

var interpreter = new Interpreter();
var result = interpreter.Eval("8 / 2 + 2");

ou

var interpreter = new Interpreter()
                .SetVariable("service", new ServiceExample());

string expression = "x > 4 ? service.aMethod() : service.AnotherMethod()";

Lambda parsedExpression = interpreter.Parse(expression, 
                        new Parameter("x", typeof(int)));

parsedExpression.Invoke(5);

Meu trabalho é baseado no artigo de Scott Gu http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .

Tópico antigo, mas considerando que este é um dos primeiros tópicos que aparecem ao pesquisar no Google, aqui está uma solução atualizada.

Você pode usar Nova API de script de Roslyn para avaliar expressões.

Se você estiver usando o NuGet, basta adicionar uma dependência ao Microsoft.CodeAnalysis.CSharp.Scripting.Para avaliar os exemplos que você forneceu, é tão simples quanto:

var result = CSharpScript.EvaluateAsync("1 + 3").Result;

Obviamente, isso não utiliza os recursos assíncronos do mecanismo de script.

Você também pode especificar o tipo de resultado avaliado conforme pretendido:

var now = CSharpScript.EvaluateAsync<string>("System.DateTime.Now.ToString()").Result;

Para avaliar trechos de código mais avançados, passar parâmetros, fornecer referências, namespaces e outros enfeites, verifique o wiki com link acima.

Se você deseja especificamente chamar código e assemblies em seu próprio projeto, eu recomendaria usar o C# CodeDom CodeProvider.

Aqui está uma lista das abordagens mais populares que conheço para avaliar expressões de string dinamicamente em C#.

Soluções Microsoft

Soluções que não são da Microsoft (não que haja algo de errado com isso)

using System;
using Microsoft.JScript;
using Microsoft.JScript.Vsa;
using Convert = Microsoft.JScript.Convert;

namespace System
{
    public class MathEvaluator : INeedEngine
    {
        private VsaEngine vsaEngine;

        public virtual String Evaluate(string expr)
        {
            var engine = (INeedEngine)this;
            var result = Eval.JScriptEvaluate(expr, engine.GetEngine());

            return Convert.ToString(result, true);
        }

        VsaEngine INeedEngine.GetEngine()
        {
            vsaEngine = vsaEngine ?? VsaEngine.CreateEngineWithType(this.GetType().TypeHandle);
            return vsaEngine;
        }

        void INeedEngine.SetEngine(VsaEngine engine)
        {
            vsaEngine = engine;
        }
    }
}

Quais são as implicações de desempenho de fazer isso?

Usamos um sistema baseado em algo como o mencionado acima, onde cada script C# é compilado em um assembly na memória e executado em um AppDomain separado.Ainda não existe um sistema de cache, então os scripts são recompilados toda vez que são executados.Fiz alguns testes simples e um script "Hello World" muito simples é compilado em cerca de 0,7 segundos na minha máquina, incluindo o carregamento do script do disco.0,7 segundos é bom para um sistema de script, mas pode ser muito lento para responder à entrada do usuário; nesse caso, um analisador/compilador dedicado como o Flee pode ser melhor.

using System;
public class Test
{
    static public void DoStuff( Scripting.IJob Job)
    {
        Console.WriteLine( "Heps" );
    }
}

Parece que também existe uma maneira de fazer isso usando RegEx e XPathNavigator para avaliar a expressão.Ainda não tive oportunidade de testá-lo, mas gostei porque não exigia compilar código em tempo de execução ou usar bibliotecas que não poderiam estar disponíveis.

http://www.webtips.co.in/c/evaluate-function-in-c-net-as-eval-function-in-javascript.aspx

Vou tentar e depois conto se funcionou.Também pretendo experimentar no Silverlight, mas já é tarde e estou quase dormindo para fazer isso agora.

Embora o C# não tenha suporte nativo para um método Eval, tenho um programa de avaliação C# que permite avaliar o código C#.Ele fornece avaliação de código C# em tempo de execução e oferece suporte a muitas instruções C#.Na verdade, esse código pode ser usado em qualquer projeto .NET, porém, está limitado ao uso da sintaxe C#.Dê uma olhada no meu site, http://csharp-eval.com, para obter detalhes adicionais.

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