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

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

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;

}  

Зачем это нужно? Я очень сомневаюсь, что это лучший дизайн для ваших целей. Скорее всего, существуют другие механизмы для получения желаемых результатов, не открывая огромную банку червей (для безопасности и удобства обслуживания), которые оценивают фрагменты кода во время выполнения.

Wedge 11.09.2008 02:14

Мне нужен был быстрый и грязный способ добавить проверку выражений к написанному мной DSL. Я контролирую файлы, передаваемые оценщику, поэтому банка с червями никогда не открывается;) Кроме того, я разрешаю только одно выражение, не добавляю никаких пространств имен / не ссылаюсь на какие-либо сборки. Это должно удержать меня от причинения вреда!

Daren Thomas 11.09.2008 10:35

Я делаю это в сценариях тестирования. У меня есть сборка, которая меняет номера версий по мере обновления. Я бы хотел, чтобы мой тестовый код был «поздно привязан» к сборке - чтобы иметь возможность загружать сборку и вызывать ее динамически. это простой вопрос размышлений. Но когда я хочу реализовать интерфейс, указанный в сборке, это требует динамической компиляции кода, потому что сам интерфейс имеет строгое имя (с номером версии). У меня не может быть кода, реализующего IFoo v1.2, когда я хочу вызвать v1.3. Это решает динамическая компиляция.

Cheeso 25.06.2009 06:49

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

Cheeso 25.06.2009 06:49

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

JJJ 10.09.2008 16:35
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
55
5
98 613
7

Ответы 7

What are the performance implications of doing this?

Мы используем систему, основанную на чем-то вроде упомянутого выше, где каждый сценарий C# компилируется в сборку в памяти и выполняется в отдельном домене приложений. Системы кеширования пока нет, поэтому скрипты перекомпилируются каждый раз при запуске. Я провел простое тестирование, и очень простой сценарий «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, но уже слишком поздно, и я почти сплю, чтобы сделать это сейчас.

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

Есть лучшая реализация JavaScript под названием Iron JS. Он использовал DLR, например Iron Python и т. д. Iron Js на NuGet. Как я понял Vsa устарела

Jeno Laszlo 22.07.2011 13:34

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

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

+1 @Davide lcardi, это очень хорошая библиотека, но с некоторыми ограничениями: stackoverflow.com/questions/46581067/…

Dabbas 05.10.2017 11:28

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

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

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

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

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

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

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

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

Мне нравится эта функция, и она работает очень хорошо, единственная жалоба заключалась в том, насколько она медленная.

JMIII 03.08.2018 23:25

Ужасно медленно. добавляет 30 секунд для вычисления 40 простых третичных выражений

hungryMind 12.05.2020 16:54

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

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

Решения Microsoft

Решения сторонних производителей (не то чтобы в этом что-то не так)

Кажется, вы упустили несколько вариантов (некоторые в других ответах здесь), такие как DataColumn.Expression и DataTable.Compute и устаревший JScript.

NetMage 09.10.2020 23:50

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