Я хотел бы сделать эквивалент:
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;
}
Мне нужен был быстрый и грязный способ добавить проверку выражений к написанному мной DSL. Я контролирую файлы, передаваемые оценщику, поэтому банка с червями никогда не открывается;) Кроме того, я разрешаю только одно выражение, не добавляю никаких пространств имен / не ссылаюсь на какие-либо сборки. Это должно удержать меня от причинения вреда!
Я делаю это в сценариях тестирования. У меня есть сборка, которая меняет номера версий по мере обновления. Я бы хотел, чтобы мой тестовый код был «поздно привязан» к сборке - чтобы иметь возможность загружать сборку и вызывать ее динамически. это простой вопрос размышлений. Но когда я хочу реализовать интерфейс, указанный в сборке, это требует динамической компиляции кода, потому что сам интерфейс имеет строгое имя (с номером версии). У меня не может быть кода, реализующего IFoo v1.2, когда я хочу вызвать v1.3. Это решает динамическая компиляция.
Должен сказать, есть и другие сценарии. Это не обычное дело, но есть много сценариев, в которых динамическая компиляция кода имеет смысл.
Помните, что если вы не выполняете компиляцию и выполнение в отдельном домене приложения, вы можете столкнуться с проблемами памяти. Сборки, созданные таким образом, не могут быть выгружены, но если вы создаете сборку в отдельном AppDomain, вы можете выгрузить AppDomain и тем самым выгрузить сгенерированную сборку.





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 устарела
Хотя 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/…
Старая тема, но, учитывая, что это одна из первых тем, появляющихся при поиске в 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;
Чтобы оценить более сложные фрагменты кода, передать параметры, предоставить ссылки, пространства имен и многое другое, проверьте вики, указанную выше.
Мне нравится эта функция, и она работает очень хорошо, единственная жалоба заключалась в том, насколько она медленная.
Ужасно медленно. добавляет 30 секунд для вычисления 40 простых третичных выражений
Если вы специально хотите вызвать код и сборки в своем собственном проекте, я бы рекомендовал использовать C# CodeDom CodeProvider.
Вот список наиболее популярных мне известных подходов для динамического вычисления строковых выражений в C#.
Кажется, вы упустили несколько вариантов (некоторые в других ответах здесь), такие как DataColumn.Expression и DataTable.Compute и устаревший JScript.
Зачем это нужно? Я очень сомневаюсь, что это лучший дизайн для ваших целей. Скорее всего, существуют другие механизмы для получения желаемых результатов, не открывая огромную банку червей (для безопасности и удобства обслуживания), которые оценивают фрагменты кода во время выполнения.