如何dynamic评估C#代码?

我可以做一个eval("something()"); 在JavaScript中dynamic执行代码。 有没有办法让我在C#中做同样的事情?

我正在尝试做的是,我有一个整型variables(比如i ),我有名称的多个属性:“Property1”,“Property2”,“Property3”等现在,我想执行一些操作“财产 ”财产取决于i的价值。

这是非常简单的Javascript。 有没有办法用C#做到这一点?

不幸的是,C#不是一个像这样的dynamic语言。

然而,你可以做的是创build一个C#源代码文件,包含类和所有东西,并通过CodeDom提供程序运行C#并将其编译成汇编,然后执行它。

MSDN上的这个论坛post包含了一些有关代码的例子。
从一个string创build一个匿名方法?

我几乎不会说这是一个很好的解决scheme,但无论如何也是可能的。

你想在这个string中使用什么样的代码? 如果它是有效代码的一小部分,例如只是mathexpression式,则可能存在其他替代scheme。


编辑 :那么,教我先阅读问题。 是的,反思会在这里给你一些帮助。

如果你把string分开, 首先,要获取单独的属性,可以使用以下代码为某个类的特定属性获取PropertyInfo对象,然后使用该对象来操作特定的对象。

 String propName = "Text"; PropertyInfo pi = someObject.GetType().GetProperty(propName); pi.SetValue(someObject, "New Value", new Object[0]); 

链接: PropertyInfo.SetValue方法

不是真的。 你可以使用reflection来达到你想要的效果,但是它不会像Javascript那样简单。 例如,如果你想将一个对象的私有字段设置为某个东西,你可以使用这个函数:

 protected static void SetField(object o, string fieldName, object value) { FieldInfo field = o.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic); field.SetValue(o, value); } 

所有这一切肯定会奏效。 就个人而言,对于这个特殊的问题,我可能会采取一些不同的方法。 也许这样的事情:

 class MyClass { public Point point1, point2, point3; private Point[] points; public MyClass() { //... this.points = new Point[] {point1, point2, point3}; } public void DoSomethingWith(int i) { Point target = this.points[i+1]; // do stuff to target } } 

当使用这样的模式时,您必须小心,您的数据按引用存储,而不是按值存储。 换句话说,不要用原语做这件事。 你必须使用他们臃肿的类同行。

我意识到这不完全是个问题,但是这个问题已经得到了很好的回答,我想也许另一种方法可能会有所帮助。

这是一个在C#下的eval函数。 我用它来从string转换匿名函数(Lambdaexpression式)。 来源: http : //www.codeproject.com/KB/cs/evalcscode.aspx

 public static object Eval(string sCSCode) { CSharpCodeProvider c = new CSharpCodeProvider(); ICodeCompiler icc = c.CreateCompiler(); CompilerParameters cp = new CompilerParameters(); cp.ReferencedAssemblies.Add("system.dll"); cp.ReferencedAssemblies.Add("system.xml.dll"); cp.ReferencedAssemblies.Add("system.data.dll"); cp.ReferencedAssemblies.Add("system.windows.forms.dll"); cp.ReferencedAssemblies.Add("system.drawing.dll"); cp.CompilerOptions = "/t:library"; cp.GenerateInMemory = true; StringBuilder sb = new StringBuilder(""); sb.Append("using System;\n" ); sb.Append("using System.Xml;\n"); sb.Append("using System.Data;\n"); sb.Append("using System.Data.SqlClient;\n"); sb.Append("using System.Windows.Forms;\n"); sb.Append("using System.Drawing;\n"); sb.Append("namespace CSCodeEvaler{ \n"); sb.Append("public class CSCodeEvaler{ \n"); sb.Append("public object EvalCode(){\n"); sb.Append("return "+sCSCode+"; \n"); sb.Append("} \n"); sb.Append("} \n"); sb.Append("}\n"); CompilerResults cr = icc.CompileAssemblyFromSource(cp, sb.ToString()); if( cr.Errors.Count > 0 ){ MessageBox.Show("ERROR: " + cr.Errors[0].ErrorText, "Error evaluating cs code", MessageBoxButtons.OK, MessageBoxIcon.Error ); return null; } 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#语句,我现在不用,但是你已经可以在C#2.0中执行Javascript语句了。 开源库Jint能够做到这一点。 这是一个.NET的Javascript解释器。 通过一个JavaScript程序,它会运行在您的应用程序。 你甚至可以传递C#对象作为参数,并对其进行自动化。

另外如果你只是想评估你的属性expression式,试试看NCalc 。

我写了一个开源项目Dynamic Expresso ,它可以将使用C#语法编写的文本expression式转换为委托(或expression式树)。 expression式被parsing并转换成expression式树而不使用编译或reflection。

你可以写下如下的东西:

 var interpreter = new Interpreter(); var result = interpreter.Eval("8 / 2 + 2"); 

要么

 var interpreter = new Interpreter() .SetVariable("service", new ServiceExample()); string expression = "x > 4 ? service.SomeMethod() : service.AnotherMethod()"; Lambda parsedExpression = interpreter.Parse(expression, new Parameter("x", typeof(int))); parsedExpression.Invoke(5); 

我的工作基于Scott Gu的文章http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

使用Roslyn脚本API(更多示例在这里 ):

 // add NuGet package 'Microsoft.CodeAnalysis.Scripting' using Microsoft.CodeAnalysis.CSharp.Scripting; await CSharpScript.EvaluateAsync("System.Math.Pow(2, 4)") // returns 16 

你也可以运行任何一段代码:

 var script = await CSharpScript.RunAsync(@" class MyClass { public void Print() => System.Console.WriteLine(1); }") 

并引用之前运行中生成的代码:

 await script.ContinueWithAsync("new MyClass().Print();"); 

您可以使用reflection来获取属性并调用它。 像这样的东西:

 object result = theObject.GetType().GetProperty("Property" + i).GetValue(theObject, null); 

也就是说,假设具有该属性的对象被称为“theObject”:)

你也可以实现一个Webbrowser,然后加载一个包含javascript的html文件。

然后你去这个浏览器的document.InvokeScript .vokeScript方法。 eval函数的返回值可以被捕获并转换成你需要的所有东西。

我在几个项目中做了这个,它完美的工作。

希望它有帮助

你可以用一个原型函数来做到这一点:

 void something(int i, string P1) { something(i, P1, String.Empty); } void something(int i, string P1, string P2) { something(i, P1, P2, String.Empty); } void something(int i, string P1, string P2, string P3) { something(i, P1, P2, P3, String.Empty); } 

等等…

在运行时使用reflection来parsing和评估针对对象的数据绑定expression式。

DataBinder.Eval方法

我写了一个包SharpByte.Dynamic来简化dynamic编译和执行代码的任务。 可以使用扩展方法在任何上下文对象上调用该代码,如此处所述 。

例如,

 someObject.Evaluate<int>("6 / {{{0}}}", 3)) 

返回3;

 someObject.Evaluate("this.ToString()")) 

返回上下文对象的string表示;

 someObject.Execute(@ "Console.WriteLine(""Hello, world!""); Console.WriteLine(""This demonstrates running a simple script""); "); 

作为脚本运行这些语句等

如此处所示,可以使用工厂方法轻松地获得可执行文件,所有您需要的是源代码和任何预期命名参数列表(令牌使用三个括号表示法embedded,例如{{{0}} },以避免与string.Format()以及Handlebars-like语法的冲突):

 IExecutable executable = ExecutableFactory.Default.GetExecutable(executableType, sourceCode, parameterNames, addedNamespaces); 

每个可执行对象(脚本或expression式)都是线程安全的,可以被存储和重用,支持从脚本内进行日志logging,存储定时信息和遇到的最后一个exception等。还有一个Copy()方法,创build便宜的副本,即使用从脚本或expression式编译的可执行对象作为创build其他模板的模板。

执行已编译的脚本或语句的开销相对较低,在适中的硬件上稍微低于微秒,已编译的脚本和expression式被caching以供重用。

不幸的是,C#没有任何原生设施来完成你所要求的。

但是,我的C#eval程序确实允许评估C#代码。 它提供了在运行时评估C#代码并支持许多C#语句。 实际上,这个代码在任何.NET项目中都是可用的,但是它仅限于使用C#语法。 看看我的网站http://csharp-eval.com ,了解更多详情。

正确的答案是你需要caching所有的结果,以保持记忆体使用率低。

一个例子看起来像这样

 TypeOf(Evaluate) { "1+1":2; "1+2":3; "1+3":5; .... "2-5":-3; "0+0":1 } 

并将其添加到列表

 List<string> results = new List<string>(); for() results.Add(result); 

保存该id并在代码中使用它

希望这可以帮助