我想做相当于:
object result = Eval("1 + 3");
string now = Eval("System.DateTime.Now().ToString()") as string
在 Biri 的链接之后,我得到了这个片段(修改以删除过时的方法
ICodeCompiler.CreateCompiler()
:
private object Eval(string sExpression)
{
CSharpCodeProvider c = new CSharpCodeProvider();
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("system.dll");
cp.CompilerOptions = "/t:library";
cp.GenerateInMemory = true;
StringBuilder sb = new StringBuilder("");
sb.Append("using System;\n");
sb.Append("namespace CSCodeEvaler{ \n");
sb.Append("public class CSCodeEvaler{ \n");
sb.Append("public object EvalCode(){\n");
sb.Append("return " + sExpression + "; \n");
sb.Append("} \n");
sb.Append("} \n");
sb.Append("}\n");
CompilerResults cr = c.CompileAssemblyFromSource(cp, sb.ToString());
if (cr.Errors.Count > 0)
{
throw new InvalidExpressionException(
string.Format("Error ({0}) evaluating: {1}",
cr.Errors[0].ErrorText, sExpression));
}
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;
}
老话题,但考虑到这是谷歌搜索时出现的第一个线程,这里有一个更新的解决方案。
您可以使用 Roslyn 的新脚本 API 来计算表达式。
如果您使用的是 NuGet,只需将依赖项添加到 Microsoft.CodeAnalysis.CSharp.Scripting。 要评估您提供的示例,很简单:
var result = CSharpScript.EvaluateAsync("1 + 3").Result;
这显然没有利用脚本引擎的异步功能。
您还可以根据需要指定评估结果类型:
var now = CSharpScript.EvaluateAsync<string>("System.DateTime.Now.ToString()").Result;
要评估更高级的代码片段、传递参数、提供引用、命名空间等等,请查看上面链接的 wiki。
我写了一个开源项目,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.aMethod() : 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.
如果您特别想调用自己项目中的代码和程序集,我会提倡使用 C# CodeDom CodeProvider。
这里列出了我所知道的在 C# 中动态评估字符串表达式的最流行的方法。
using System;
using Microsoft.JScript;
using Microsoft.JScript.Vsa;
using Convert = Microsoft.JScript.Convert;
namespace System
{
public class MathEvaluator : INeedEngine
{
private VsaEngine vsaEngine;
public virtual String Evaluate(string expr)
{
var engine = (INeedEngine)this;
var result = Eval.JScriptEvaluate(expr, engine.GetEngine());
return Convert.ToString(result, true);
}
VsaEngine INeedEngine.GetEngine()
{
vsaEngine = vsaEngine ?? VsaEngine.CreateEngineWithType(this.GetType().TypeHandle);
return vsaEngine;
}
void INeedEngine.SetEngine(VsaEngine engine)
{
vsaEngine = engine;
}
}
}
这样做对性能有何影响?
我们使用基于类似上述内容的系统,其中每个 C# 脚本都被编译为内存中的程序集,并在单独的 AppDomain 中执行。目前还没有缓存系统,因此脚本每次运行时都会重新编译。我已经做了一些简单的测试,一个非常简单的“Hello World”脚本在我的机器上编译大约需要 0.7 秒,包括从磁盘加载脚本。 0.7 秒对于脚本系统来说已经足够了,但对于响应用户输入来说可能太慢了,在这种情况下,像 Flee 这样的专用解析器/编译器可能会更好。
using System;
public class Test
{
static public void DoStuff( Scripting.IJob Job)
{
Console.WriteLine( "Heps" );
}
}
我刚刚用纯 C# 编写了一个类似的库 (Matheval)。 它允许像 excel 公式一样评估字符串和数字表达式。
using System;
using org.matheval;
public class Program
{
public static void Main()
{
Expression expression = new Expression("IF(time>8, (HOUR_SALARY*8) + (HOUR_SALARY*1.25*(time-8)), HOUR_SALARY*time)");
//bind variable
expression.Bind("HOUR_SALARY", 10);
expression.Bind("time", 9);
//eval
Decimal salary = expression.Eval<Decimal>();
Console.WriteLine(salary);
}
}
看起来还有一种方法可以使用 RegEx 和 XPathNavigator 来评估表达式。我还没有机会测试它,但我有点喜欢它,因为它不需要在运行时编译代码或使用无法使用的库。
http://www.webtips.co.in/c/evaluate-function-in-c-net-as-eval-function-in-javascript.aspx
我会尝试一下,如果有效,稍后再说。我也打算在 Silverlight 中尝试它,但为时已晚,我现在都快睡着了。
虽然 C# 本身不支持 Eval 方法,但我有一个 C# eval 程序允许评估 C# 代码。它提供在运行时评估 C# 代码并支持许多 C# 语句。事实上,此代码可在任何 .NET 项目中使用,但仅限于使用 C# 语法。看看我的网站,http://csharp-eval.com,了解更多详情。
下载这个并把它做成一个类库,可以在你的项目中引用。这似乎非常快速和简单
也许这会有所帮助!
只需使用连接字符串将算术表达式传递给 sql
// INPUT
string eval = "SELECT ((1+2)-3*4)/5.0";
string strCon = $"Server=.\sqlexpress; Database=master; integrated security = true";
SqlConnection sqlCon = new SqlConnection(strCon);
sqlCon.Open();
SqlCommand cmd = new SqlCommand(eval, sqlCon);
SqlDataAdapter da = new SqlDataAdapter(cmd);
string result = da.SelectCommand.ExecuteScalar().ToString();
// OUTPUT
Console.WriteLine(result);
你必须添加 使用 System.Data.SqlClient;