我如何动态评估C#代码?

我可以使用 eval(“something()”); 在JavaScript中动态执行代码。有没有办法让我在C#中做同样的事情?

我想要做的一个例子是:我有一个整型变量(比如 i ),并且我有多个属性,名称分别为:“Property1”,“Property2”,“Property3”等。 现在,我想根据 i 的值在“Property i ”属性上执行一些操作。

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

0
@Peter Long,我可以在哪里找到关于IronPython eval的文档?
额外 作者 smartcaveman,
c#调用ironpython的eval。我在c#4.0中试过。没有C#2.0的经验
额外 作者 Peter Long,
额外 作者 Igor Brejc,

15 答案

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

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

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

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

0
额外

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

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

等等...

0
额外

不是真的。你可以使用反射来达到你想要的效果,但它不会像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);
}
0
额外

不幸的是,C#不是那种动态语言。

但是,您可以做的是创建一个C#源代码文件,该文件充满了类和所有内容,并通过CodeDom提供程序为C#运行它,并将其编译为程序集,然后执行它。

This forum post on MSDN contains an answer with some example code down the page somewhat:
create a anonymous method from a string?

我几乎不会说这是一个非常好的解决方案,但它有可能。

你希望在那个字符串中使用什么样的代码?如果它是有效代码的次要子集,例如只是数学表达式,则可能存在其他替代方案。


Edit: Well, that teaches me to read the questions thoroughly first. Yes, reflection would be able to give you some help here.

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

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

Link: PropertyInfo.SetValue Method

0
额外

我编写了一个开源项目 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.SomeMethod() : service.AnotherMethod()";

Lambda parsedExpression = interpreter.Parse(expression, 
                          new Parameter("x", typeof(int)));

parsedExpression.Invoke(5);

My w要么k is based on Scott Gu article http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx .

0
额外

在运行时使用反射来解析和评估针对对象的数据绑定表达式。

DataBinder.Eval方法

0
额外
你能举一个例子吗?
额外 作者 Nick Binnet,

如果您绝对想要执行C#语句,但现在不用,但您已经可以在C#2.0中执行Javascript语句。开源库 Jint 能够做到。这是一个.NET的Javascript解释器。通过一个JavaScript程序,它将在您的应用程序中运行。你甚至可以传递C#对象作为参数,并对其进行自动化。

另外,如果您只想评估您的物业表达,请尝试 NCalc

0
额外

使用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();");
0
额外

不幸的是,C#没有任何本地功能来完成你所要求的功能。

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

0
额外
额外 作者 Andrey-WD,

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

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

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

0
额外

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

然后你在这个浏览器上找到 document.InvokeScript 方法。 eval函数的返回值可以被捕获并转换为您需要的一切。

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

希望能帮助到你

0
额外

This is an eval function under c#. I used it to convert anonymous functions (Lambda Expressions) from a string. Source: 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;

}
0
额外
@sehe呃,我纠正了错字(Lambada => Lambda)。我不知道这首歌叫做Lambada,所以这是一个无意的故事。 ;)
额外 作者 Largo,

正确的答案是你需要缓存所有的结果来保持mem0ry的使用率低。

一个例子看起来像这样

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

并将其添加到列表中

List results = new List();
for() results.Add(result);

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

希望这可以帮助

0
额外
有人将查询与评估混淆在一起。如果你知道所有可能的程序(我认为至少是NP-Hard)......并且你有一台超级机器来预编译所有可能的结果...... 没有副作用/外部输入...是的,这个想法理论上是可行的。虽然这个代码是一个很大的语法错误
额外 作者 sehe,
嗯...你是什么意思?
额外 作者 xfix,

我已经写了一个包, SharpByte 。动态,以简化动态编译和执行代码的任务。可以使用扩展方法在任何上下文对象上调用该代码,详见这里

例如,

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

返回3;

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

返回上下文对象的字符串表示;

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

将这些语句作为脚本运行等等。

Executables can be gotten easily using a factory method, as seen in the example here--all you need is the source code and list of any expected named parameters (tokens are embedded using triple-bracket notation, such as {{{0}}}, to avoid collisions with string.Format() as well as Handlebars-like syntaxes):

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

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

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

0
额外

我试图通过它的名字来获得结构(类)成员的值。结构不是动态的。直到我终于明白了,所有的答案都无法解决:

public static object GetPropertyValue(object instance, string memberName)
{
    return instance.GetType().GetField(memberName).GetValue(instance);
}

该方法将通过名称返回成员的值。它适用于规则结构(类)。

0
额外