首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >CSharpScript:动态脚本参数名

CSharpScript:动态脚本参数名
EN

Stack Overflow用户
提问于 2019-11-22 09:02:07
回答 1查看 2.2K关注 0票数 1

我试图使用Roslyn来执行用户在运行时定义的C#代码,类似于下面的示例:

代码语言:javascript
复制
public class Globals
{
    public int X;
    public int Y;
}
var globals = new Globals { X = 1, Y = 2 };
Console.WriteLine(await CSharpScript.EvaluateAsync<int>("X+Y", globals: globals));

从这里复制的示例

我的问题是,脚本中使用的变量名在编译时是未知的。换句话说,我不知道我的globals类应该使用哪些成员名,也不知道将有多少成员(脚本参数)。

我试着用ExpandoObject来解决这个问题,但没能让它起作用。ExpandoObject应该在这种情况下工作吗?还有其他方法来解决这个问题吗?

更新

对于我的用例,最好的解决方案可能是使用System.Linq.Dynamic

代码语言:javascript
复制
//Expression typed in by the user at runtime
string Exp = @"A + B > C";

//The number of variables and their names are given elsewhere,
//so the parameter-array doesn't need to be hardcoded like in this example.
var e = System.Linq.Dynamic.DynamicExpression.ParseLambda(new[] 
{
    Expression.Parameter(typeof(double), "A"),
    Expression.Parameter(typeof(double), "B"),
    Expression.Parameter(typeof(double), "C")
}, 
null, Exp);

var Lambda = e.Compile();

//Fake some updates...
foreach (var i in Enumerable.Range(0,10))
{
    Console.WriteLine(Lambda.DynamicInvoke(i, 3, 10));
}
EN

回答 1

Stack Overflow用户

发布于 2019-11-22 19:37:45

如果可以在运行时检索所有成员名称、它们的计数以及从输入中传递的值,则可以在运行时生成执行代码并对其进行评估。作为执行代码的一个简单示例,您可以为所有输入值生成变量声明,然后对所有这些值进行求和:

代码语言:javascript
复制
// here you should put retrieved member names and their values. Just  for example, currently here exist a couple of args
var variablesAndValues = new Dictionary<string, object> { ["arg_1"] = 5, ["arg_2"] = 6, ["arg_3"] = 7 };

// and you should create an execution code looks like this:
// var arg_1 = value_1;
// ..
// var arg_n = value_n;
// arg_1 + .. + arg_n
StringBuilder builder = new StringBuilder();
foreach (var item in variablesAndValues)
{
    builder.Append("var ").Append(item.Key).Append(" = ").Append(item.Value).AppendLine(";");
}

var variablesCount = variablesAndValues.Count;
foreach (var item in variablesAndValues.Keys)
{
    builder.Append(item);
    if (--variablesCount > 0)
    {
        builder.Append(" + ");
    }
}

var scriptState = CSharpScript.RunAsync(builder.ToString()).Result;
var result = scriptState.ReturnValue;

请注意,此示例假设所有值类型都具有sum_operation,并且在默认脚本选项中它们是已知的,否则在尝试执行代码时会收到编译错误。

Upd。

如果您的情况是性能严格的,您可以创建一个脚本,该脚本将对所有输入参数进行求和,然后在需要时重复运行该脚本。

代码语言:javascript
复制
public class Globals
{
    public int[] Args;
}
...

// create script that sum all input arguments
var script = CSharpScript.Create(@"var result = 0;
foreach (var item in Args)
{
    result += item;
}
return result; ", globalsType: typeof(Globals));

// run it at twice on the user values that were received before
// also you can reuse an array, but anyway
var res1 = script.RunAsync(new Globals { Args = new[] { 5, 6, 7 } }).Result.ReturnValue;
var res2 = script.RunAsync(new Globals { Args = new[] { 7, 8, 9, 10} }).Result.ReturnValue;

这种方法在脚本代码中忽略了来自用户的输入变量名,而且在您的情况下似乎并不重要。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58990746

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档