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

StackOverflow https://stackoverflow.com/questions/53844

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

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

}  
Это было полезно?

Решение

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

Или с помощью Бежать, что происходит по той же причине.

Другие советы

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

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

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 .

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

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

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

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

Очевидно, что при этом не используются асинхронные возможности скриптового движка.

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

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

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

Если вы специально хотите вызывать код и сборки в своем собственном проекте, я бы рекомендовал использовать C# CodeDom CodeProvider.

Вот список самых популярных известных мне подходов к динамическому вычислению строковых выражений в C#.

Решения Майкрософт

Решения сторонних производителей (хотя в этом нет ничего плохого)

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top