代码之家  ›  专栏  ›  技术社区  ›  Adhip Gupta Miguel Angelo

如何动态评估C代码?

  •  82
  • Adhip Gupta Miguel Angelo  · 技术社区  · 18 年前

    我可以做一个 eval("something()"); 在javascript中动态执行代码。我有没有办法用C语言做同样的事情?

    我要做的一个例子是:我有一个整数变量(比如 i )我有多个属性的名字:“属性1”、“属性2”、“属性3”等等。 现在,我想对“属性”执行一些操作 “属性取决于 .

    这对于JavaScript来说非常简单。有没有办法用C来做这个?

    16 回复  |  直到 8 年前
        1
  •  49
  •   Dan Atkinson    11 年前

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

    然而,您可以做的是创建一个包含类和所有内容的C源代码文件,并通过C的codedom提供程序运行它,然后将其编译成一个程序集,然后执行它。

    这个在msdn上的论坛帖子包含了一个答案,页面下面有一些示例代码:
    create a anonymous method from a string?

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

    您希望在该字符串中使用哪种代码?如果它是有效代码的一个子集,例如,仅仅是数学表达式,那么可能存在其他的替代方法。


    编辑 好吧,那教我先把问题读清楚。是的,反思可以给你一些帮助。

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

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

    链接: PropertyInfo.SetValue Method

        2
  •  15
  •   Eli Arbel    10 年前

    使用Roslyn脚本API(更多 samples here ):

    // 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();");
    
        3
  •  14
  •   Markus Safar    10 年前

    不是真的。您可以使用反射来实现您想要的,但它不会像在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);
    }
    
        4
  •  9
  •   Largo    14 年前

    这是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;
    
    }
    
        5
  •  9
  •   Markus Safar    10 年前

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

    你可以写一些像:

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

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

        6
  •  7
  •   MojoFilter    18 年前

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

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

    当使用这样的模式时,必须注意数据是通过引用而不是通过值存储的。换句话说,不要用原语来做这个。你必须使用他们那些臃肿的同班同学。

    我意识到这不完全是问题所在,但问题已经得到了很好的回答,我想也许有一种替代方法可以帮上忙。

        7
  •  5
  •   Sébastien Ros - MSFT    16 年前

    如果您确实想执行C语句,我现在不想,但是您已经可以在C 2.0中执行javascript语句了。开放源码库 Jint 能够做到。它是一个.NET的javascript解释器。通过一个javascript程序,它将在应用程序内部运行。甚至可以将C对象作为参数传递,并对其进行自动化。

    另外,如果只想对属性的表达式进行计算,请尝试 NCalc .

        8
  •  4
  •   David Wengier    18 年前

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

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

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

        9
  •  2
  •   Otiel user577803    14 年前

    您还可以实现WebBrowser,然后加载包含javascript的HTML文件。

    然后你去 document.InvokeScript 方法。eval函数的返回值可以被捕获并转换为所需的一切。

    我在几个项目中做了这个,它工作得很好。

    希望它有帮助

        10
  •  0
  •   GateKiller    18 年前

    你可以用一个原型函数来完成它:

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

    等等…

        11
  •  0
  •   Jan Bannister    13 年前

    使用反射在运行时针对对象分析和计算数据绑定表达式。

    DataBinder.Eval Method

        12
  •  0
  •   Iucounu    9 年前

    我写了一个包裹, SharpByte.Dynamic 以简化动态编译和执行代码的任务。可以使用扩展方法在任何上下文对象上调用代码,详情如下 here .

    例如,

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

    回报率3;

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

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

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

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

    可执行文件可以很容易地使用工厂方法获得,如示例中所示。 here --您所需要的只是源代码和任何预期命名参数的列表(标记是使用三方括号表示法嵌入的,如0,以避免与string.format()以及诸如syntaxes之类的手把冲突):

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

    每个可执行对象(脚本或表达式)都是线程安全的,可以存储和重用,支持从脚本中进行日志记录,存储计时信息和最后一个异常(如果遇到),等等。每个对象上还编译了copy()方法,以允许创建便宜的副本,即使用从脚本或表达式编译的可执行对象作为项。创造他人的板。

    执行一个已经编译的脚本或语句的开销相对较低,在中等的硬件上只需一微秒,并且已经编译的脚本和表达式被缓存以供重用。

        13
  •  0
  •   Ilya Dan    8 年前

    我试图通过一个结构(类)成员的名称来获取它的值。结构不是动态的。直到我最终得到答案,所有的答案才奏效:

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

    此方法将按成员的名称返回其值。它在规则结构(类)上工作。

        14
  •  0
  •   Hennadii    8 年前

    你可以查一下 Heleonix.Reflection 图书馆。它提供了动态获取/设置/调用成员(包括嵌套成员)的方法,或者如果明确定义了成员,则可以创建比反射更快的getter/setter(lambda编译为委托):

    var success = Reflector.Set(instance, null, $"Property{i}", value);
    

    或者,如果属性的数量不是无限的,则可以生成setter并对其进行修改(setter更快,因为它们是编译的委托):

    var setter = Reflector.CreateSetter<object, object>($"Property{i}", typeof(type which contains "Property"+i));
    setter(instance, value);
    

    setter不能是类型 Action<object, object> 但是实例在运行时可能不同,所以您可以创建setter列表。

        15
  •  -2
  •   xnaterm    15 年前

    不幸的是,C没有任何本地设施来满足您的要求。

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

        16
  •  -8
  •   roft    15 年前

    正确的答案是,您需要缓存所有结果,以保持内存使用率低。

    示例如下

    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并在代码中使用

    希望这有帮助