C# 是否可以在 .NET 中在运行时编译和执行新代码?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/234217/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:14:47  来源:igfitidea点击:

Is it possible to compile and execute new code at runtime in .NET?

c#.netcompilationruntime

提问by raven

Note: Mathematical expression evaluation is not the focus of this question. I want to compile and execute new code at runtime in .NET.That being said...

注意:数学表达式求值不是本题的重点。我想在运行时在 .NET 中编译和执行新代码。话虽如此...

I would like to allow the user to enter any equation, like the following, into a text box:

我想允许用户在文本框中输入任何方程,如下所示:

x = x / 2 * 0.07914
x = x^2 / 5

And have that equation applied to incoming data points. The incoming data points are represented by xand each data point is processed by the user-specified equation. I did this years ago, but I didn't like the solution because it required parsing the text of the equation for every calculation:

并将该等式应用于传入的数据点。传入的数据点由x表示,每个数据点由用户指定的方程处理。我几年前就这样做了,但我不喜欢这个解决方案,因为它需要为每次计算解析方程的文本:

float ApplyEquation (string equation, float dataPoint)
{
    // parse the equation string and figure out how to do the math
    // lots of messy code here...
}

When you're processing boatloads of data points, this introduces quite a bit of overhead. I would like to be able to translate the equation into a function, on the fly, so that it only has to be parsed once. It would look something like this:

当您处理大量数据点时,这会带来相当多的开销。我希望能够将方程即时转换为函数,以便只需解析一次。它看起来像这样:

FunctionPointer foo = ConvertEquationToCode(equation);
....
x = foo(x);  // I could then apply the equation to my incoming data like this

Function ConvertEquationToCode would parse the equation and return a pointer to a function that applies the appropriate math.

函数 ConvertEquationToCode 将解析方程并返回一个指向应用适当数学的函数的指针。

The app would basically be writing new code at run time. Is this possible with .NET?

该应用程序基本上会在运行时编写新代码。这可能与 .NET 一起使用吗?

采纳答案by raven

Yes! Using methods found in the Microsoft.CSharp, System.CodeDom.Compiler, and System.Reflectionname spaces. Here is a simple console app that compiles a class ("SomeClass") with one method ("Add42") and then allows you to invoke that method. This is a bare-bones example that I formatted down to prevent scroll bars from appearing in the code display. It is just to demonstrate compiling and using new code at run time.

是的!使用在Microsoft.CSharpSystem.CodeDom.CompilerSystem.Reflection命名空间中找到的方法。这是一个简单的控制台应用程序,它使用一个方法(“Add42”)编译一个类(“SomeClass”),然后允许您调用该方法。这是一个基本示例,我对其进行了格式化以防止滚动条出现在代码显示中。只是为了演示在运行时编译和使用新代码。

using Microsoft.CSharp;
using System;
using System.CodeDom.Compiler;
using System.Reflection;

namespace RuntimeCompilationTest {
    class Program
    {
        static void Main(string[] args) {
            string sourceCode = @"
                public class SomeClass {
                    public int Add42 (int parameter) {
                        return parameter += 42;
                    }
                }";
            var compParms = new CompilerParameters{
                GenerateExecutable = false, 
                GenerateInMemory = true
            };
            var csProvider = new CSharpCodeProvider();
            CompilerResults compilerResults = 
                csProvider.CompileAssemblyFromSource(compParms, sourceCode);
            object typeInstance = 
                compilerResults.CompiledAssembly.CreateInstance("SomeClass");
            MethodInfo mi = typeInstance.GetType().GetMethod("Add42");
            int methodOutput = 
                (int)mi.Invoke(typeInstance, new object[] { 1 }); 
            Console.WriteLine(methodOutput);
            Console.ReadLine();
        }
    }
}

回答by Scott Dorman

You can try looking at either CodeDom or Lambda Expression Trees. I think either one of those should allow you to accomplish this. Expression trees are probably the better way to go but also have a higher learning curve.

您可以尝试查看 CodeDom 或 Lambda 表达式树。我认为其中任何一个都应该允许您完成此任务。表达式树可能是更好的方法,但也有更高的学习曲线。

回答by Totty

I would do a recursive function that doesn't write code but instead applies basic operators to portions of a string based on special characters found in that string. If more than one special character is found, it breaks up the string and calls itself on those two portions.

我会做一个递归函数,它不编写代码,而是根据在该字符串中找到的特殊字符将基本运算符应用于字符串的一部分。如果找到多个特殊字符,它会分解字符串并在这两个部分调用自己。

回答by cfeduke

You could start hereand if you really want to get into it, Boocan be modified to meet your needs. You could also integrate LUA with .NET. Any three of these could be utilized within the body of a delegate for your ConvertEquationToCode.

你可以从这里开始,如果你真的想进入它,可以修改Boo以满足你的需求。您还可以将LUA 与 .NET集成。这些中的任何三个都可以在代表的正文中用于您的ConvertEquationToCode.

回答by rice

Yes, definitely possible to have the user type C# into a text box, then compile that code and run it from within your app. We do that at my work to allow for custom business logic.

是的,绝对可以让用户在文本框中键入 C#,然后编译该代码并从您的应用程序中运行它。我们在我的工作中这样做是为了允许自定义业务逻辑。

Here is an article (I haven't more than skimmed it) which should get you started:

这是一篇应该让您入门的文章(我只是略读了一遍):

http://www.c-sharpcorner.com/UploadFile/ChrisBlake/RunTimeCompiler12052005045037AM/RunTimeCompiler.aspx

http://www.c-sharpcorner.com/UploadFile/ChrisBlake/RunTimeCompiler12052005045037AM/RunTimeCompiler.aspx

回答by Brian Schmitt

You might try this: Calculator.Net

你可以试试这个:Calculator.Net

It will evaluate a math expression.

它将评估数学表达式。

From the posting it will support the following:

从发布来看,它将支持以下内容:

MathEvaluator eval = new MathEvaluator();
//basic math
double result = eval.Evaluate("(2 + 1) * (1 + 2)");
//calling a function
result = eval.Evaluate("sqrt(4)");
//evaluate trigonometric 
result = eval.Evaluate("cos(pi * 45 / 180.0)");
//convert inches to feet
result = eval.Evaluate("12 [in->ft]");
//use variable
result = eval.Evaluate("answer * 10");
//add variable
eval.Variables.Add("x", 10);            
result = eval.Evaluate("x * 10");

Download PageAnd is distributed under the BSD license.

下载页面并在 BSD 许可下分发。

回答by Jon Norton

I've done this using CSharpCodeProvider by creating the boiler plate class and function stuff as a const string inside my generator class. Then I insert the user code into the boiler plate and compile.

我已经使用 CSharpCodeProvider 通过在我的生成器类中创建样板类和函数内容作为常量字符串来完成此操作。然后我将用户代码插入样板并编译。

It was fairly straightforward to do, but the danger to this approach is that the user entering the equation could enter just about anything which could be a security issue depending on your application.

这样做相当简单,但这种方法的危险在于,输入等式的用户可能会输入任何可能成为安全问题的内容,具体取决于您的应用程序。

If security is at all a concern, I would recommend using Lambda Expression Trees, but if not, using CSharpCodeProvider is a fairly robust option.

如果完全考虑安全性,我建议使用 Lambda 表达式树,但如果不是,则使用 CSharpCodeProvider 是一个相当可靠的选择。

回答by baretta

You can also create a System.Xml.XPath.XPathNavigator from an empty, "dummy" XML stream, and evaluate expressions using the XPath evaluator:

您还可以从空的“虚拟”XML 流创建 System.Xml.XPath.XPathNavigator,并使用 XPath 评估器评估表达式:

static object Evaluate ( string xp )
{
  return _nav.Evaluate ( xp );
}
static readonly System.Xml.XPath.XPathNavigator _nav
  = new System.Xml.XPath.XPathDocument (
      new StringReader ( "<r/>" ) ).CreateNavigator ( );

If you want to register variables to use within this expression, you can dynamically build XML that you can pass in the Evaluate overload that takes a XPathNodeIterator.

如果您想注册要在此表达式中使用的变量,您可以动态构建 XML,您可以在采用 XPathNodeIterator 的 Evaluate 重载中传递该 XML。

<context>
  <x>2.151</x>
  <y>231.2</y>
</context>

You can then write expressions like "x / 2 * 0.07914" and then x is the value of the node in your XML context. Another good thing is, you will have access to all XPath core functions, which includes mathematics and string manipulation methods, and more stuff.

然后,您可以编写诸如“x / 2 * 0.07914”之类的表达式,然后 x 是 XML 上下文中节点的值。另一个好处是,您将可以访问所有 XPath 核心功能,其中包括数学和字符串操作方法,以及更多内容。

If you want to take it further, you can even build your own XsltCustomContext(or ill post here on demand) where you can resolve references to extension functions and variables:

如果您想更进一步,您甚至可以构建自己的 XsltCustomContext(或按需在此处发布),您可以在其中解析对扩展函数和变量的引用:

object result = Evaluate ( "my:func(234) * $myvar" );

my:func is mapped to a C#/.NET method which takes a double or int as parameter. myvar is registered as a variable within the XSLT context.

my:func 映射到 C#/.NET 方法,该方法采用 double 或 int 作为参数。myvar 在 XSLT 上下文中注册为变量。

回答by baretta

If all else fails, there are classes under the System.Reflection.Emit namespace which you can use to produce new assemblies, classes, and methods.

如果所有其他方法都失败了,则 System.Reflection.Emit 命名空间下有一些类可用于生成新的程序集、类和方法。

回答by pyon

I don't know if it's possible to implement your ConvertEquationToCodefunction, however, you can generate a data structure that represents the calculation you need to perform.

我不知道是否可以实现您的ConvertEquationToCode功能,但是,您可以生成一个数据结构来表示您需要执行的计算。

For example, you could build a tree whose leaf nodes represent the input for your calculation, whose non-leaf nodes represent intermediate results, and whose root node represents the whole calculation.

例如,您可以构建一棵树,其叶节点代表计算的输入,非叶节点代表中间结果,根节点代表整个计算。

It has some advantages. For example, if you're doing what-if analysis and want to change the value of one input at a time, you can recalculate the results that depend on the value that you have changed, while retaining the results that don't.

它有一些优点。例如,如果您正在进行假设分析并希望一次更改一个输入的值,您可以根据您更改的值重新计算结果,同时保留未更改的结果。

回答by Roel

Try Vici.Parser: download it here (free), it's the most flexible expression parser/evaluator I've found so far.

试试 Vici.Parser:在此处下载(免费),它是迄今为止我发现的最灵活的表达式解析器/评估器。