如何动态评估C#代码?

Adh*_*pta 91 c# reflection properties c#-2.0

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

我想要做的一个例子是:我有一个整数变量(比如说i),我有多个属性名称:"Property1","Property2","Property3"等.现在,我想执行一些操作在"财产i "属性取决于的价值i.

使用Javascript这非常简单.有没有办法用C#做到这一点?

ang*_*son 50

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

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

MSDN上的这篇论坛帖子包含一些示例代码的答案:
从字符串创建一个匿名方法?

我很难说这是一个非常好的解决方案,但无论如何都是可能的.

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


编辑:嗯,这教我先彻底阅读问题.是的,反思可以在这里给你一些帮助.

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

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

链接:PropertyInfo.SetValue方法


Eli*_*bel 23

使用Roslyn脚本API(此处提供更多示例):

// add NuGet package 'Microsoft.CodeAnalysis.Scripting'
using Microsoft.CodeAnalysis.CSharp.Scripting;

await CSharpScript.EvaluateAsync("System.Math.Pow(2, 4)") // returns 16
Run Code Online (Sandbox Code Playgroud)

您还可以运行任何代码:

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

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

await script.ContinueWithAsync("new MyClass().Print();");
Run Code Online (Sandbox Code Playgroud)


Kar*_*uin 14

并不是的.您可以使用反射来实现您想要的效果,但它不会像在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);
}
Run Code Online (Sandbox Code Playgroud)


Lar*_*rgo 9

这是c#下的eval函数.我用它来从字符串转换匿名函数(Lambda表达式).资料来源: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;

}
Run Code Online (Sandbox Code Playgroud)

  • @sehe 哎呀,我更正了错字(Lambada => Lambda)。我不知道这首歌叫 Lambada,所以这首歌是无意的。;) (2认同)

Dav*_*rdi 9

我编写了一个开源项目Dynamic Expresso,它可以将使用C#语法编写的文本表达式转换为委托(或表达式树).表达式被解析并转换为表达式树而不使用编译或反射.

你可以这样写:

var interpreter = new Interpreter();
var result = interpreter.Eval("8 / 2 + 2");
Run Code Online (Sandbox Code Playgroud)

要么

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);
Run Code Online (Sandbox Code Playgroud)

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


Moj*_*ter 7

所有这些肯定会奏效.就个人而言,就个别问题而言,我可能会采取一些不同的方法.也许是这样的:

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
  }
}
Run Code Online (Sandbox Code Playgroud)

使用这样的模式时,必须注意数据是通过引用而不是按值存储的.换句话说,不要使用基元执行此操作.你必须使用他们的大臃肿类同行.

我意识到这不是问题所在,但这个问题得到了很好的回答,我想也许替代方法可能有所帮助.


Séb*_*SFT 5

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

此外,如果您只想评估属性上的表达式,请尝试NCalc.