Как я могу динамически оценить выражение C#?
-
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#.
Решения Майкрософт
- C# CodeDom CodeProvider:
- Видеть Как LINQ работал раньше и это Статья о кодпроекте
- Рослин:
- Видеть это статья об API Rosly Emit и это Ответ StackOverflow
- DataTable.Compute:
- Видеть это ответ на StackOverflow
- Веб-браузер.Document.InvokeScript
- Видеть это Вопрос StackOverflow
- DataBinder.Eval
- Скриптконтрол
- Видеть этот ответ на StackOverflow и этот вопрос
- Выполнение PowerShell:
- Видеть эта статья CodeProject
Решения сторонних производителей (хотя в этом нет ничего плохого)
- Библиотеки оценки выражений:
- Создайте свой собственный набор инструментов для создания языка, например:
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, для получения дополнительной информации.