Подтвердить что ты не робот

Как я могу оценивать выражение С# динамически?

Я хотел бы сделать эквивалент:

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

Следуя Biri s ссылка, я получил этот фрагмент (изменен для удаления устаревшего метода 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;

}  
4b9b3361

Ответ 1

Используя компиляцию "на лету", например этот пример показывает.

Или используя Flee, что по той же причине.

Ответ 2

Я написал проект с открытым исходным кодом Dynamic Expresso, который может преобразовывать текстовое выражение, написанное с использованием синтаксиса С#, в делегаты (или дерево выражений), Текстовые выражения анализируются и преобразуются в деревья выражений без использования компиляции или отражения.

Вы можете написать что-то вроде:

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

или

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

Моя работа основана на статье Скотта Гуа http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx.

Ответ 3

Старая тема, но учитывая, что это один из первых потоков, отображаемых при поиске в Интернете, вот обновленное решение.

Вы можете использовать новый API Scripting Roslyn для оценки выражений.

Если вы используете NuGet, просто добавьте зависимость от Microsoft.CodeAnalysis.CSharp.Scripting. Чтобы оценить приведенные вами примеры, это так же просто, как:

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

Это явно не использует возможности async для сценариев.

Вы также можете указать тип оцениваемого результата, который вы планировали:

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

Чтобы оценить более сложные фрагменты кода, параметры передачи, предоставить ссылки, пространства имен и многое другое, проверьте связанные с ними вики.

Ответ 4

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

Ответ 5

Каковы последствия этого для производительности?

Мы используем систему, основанную на чем-то подобном выше, где каждый С# script скомпилирован в сборку в памяти и выполняется в отдельном AppDomain. Пока нет системы кэширования, поэтому скрипты перекомпилируются каждый раз, когда они запускаются. Я провел несколько простых тестов, и очень простой "Hello World" script скомпилируется примерно за 0,7 секунды на моей машине, включая загрузку script с диска. 0,7 секунды отлично подходит для системы сценариев, но может быть слишком медленным для ответа на ввод пользователя, в этом случае выделенный анализатор/компилятор, такой как Flee, может быть лучше.

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

Ответ 6

В то время как у С# нет поддержки метода Eval изначально, у меня есть программа С# eval, которая позволяет оценивать код С#. Он обеспечивает оценку кода С# во время выполнения и поддерживает множество операторов С#. Фактически, этот код можно использовать в любом .NET-проекте, однако он ограничен синтаксисом С#. Подробнее см. на моем веб-сайте http://csharp-eval.com.

Ответ 7

Похоже, что есть способ сделать это, используя RegEx и XPathNavigator для оценки выражения. У меня не было возможности проверить его, но мне это понравилось, потому что не требовалось компилировать код во время выполнения или использовать библиотеки, которые не могли быть доступны.

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

Я попробую и расскажу позже, если это сработает. Я также намерен попробовать его в Silverlight, но уже слишком поздно, и я почти сплю, чтобы сделать это сейчас.