Как я могу оценить выражение C # динамически? - PullRequest
46 голосов
/ 10 сентября 2008

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

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;

}  

Ответы [ 8 ]

36 голосов
/ 10 сентября 2008

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

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

25 голосов
/ 08 февраля 2013

Я написал проект с открытым исходным кодом, Dynamic Expresso , который может преобразовывать текстовые выражения, написанные с использованием синтаксиса 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.

22 голосов
/ 26 апреля 2017

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

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

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

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

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

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

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

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

3 голосов
/ 07 октября 2018

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

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

Решения Microsoft

Решения сторонних разработчиков (не то, что с этим что-то не так)

2 голосов
/ 29 октября 2010
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;
        }
    }
}
1 голос
/ 10 сентября 2008

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

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

using System;
public class Test
{
    static public void DoStuff( Scripting.IJob Job)
    {
        Console.WriteLine( "Heps" );
    }
}
0 голосов
/ 10 июня 2011

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

0 голосов
/ 13 ноября 2008

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

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

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

...