如何在Roslyn脚本环境中访问和编辑全局变量?

时间:2016-04-27 13:10:49

标签: c# scripting roslyn

我有一个应用程序,我使用Roslyn脚本引擎(名称空间Microsoft.CodeAnalysis.Scripting)。

我现在拥有的是:

public static async Task<object> Execute(string code, CommandEventArgs e)
{
    if (_scriptState == null)
    {
        var options = ScriptOptions.Default;
        options
            .AddReferences(typeof (Type).Assembly,
                typeof (Console).Assembly,
                typeof (IEnumerable<>).Assembly,
                typeof (IQueryable).Assembly)
            .AddImports("System", "System.Numerics", "System.Text", "System.Linq", "System.Collections.Generics",
                "System.Security.Cryptography");
        _scriptState = await CSharpScript.RunAsync(code, options, new MessageGlobal {e = e});
    }
    else
    {
        // TODO: set global e (it's not in this variables list, thus it throws null reference)
        _scriptState.GetVariable("e").Value = e;
        _scriptState = await _scriptState.ContinueWithAsync(code);
    }
    return !string.IsNullOrEmpty(_scriptState.ReturnValue?.ToString()) ? _scriptState.ReturnValue : null;
}

为了更清楚: 在我的应用程序中,有一个事件。用户可以使用某些C#代码定义事件发生时会发生什么(此代码经常更改)。现在重点是 - 我需要将事件args传递给脚本,因此用户可以在代码中使用它。同时,我需要保持引擎状态,因为用户可能已经定义了一些他想在下次使用的变量。

我已经可以传递事件args(并在脚本中引用它像e),但只是第一次(即ScriptState为空时我创建一个新的) 。下次运行此脚本或其他脚本(ScriptState.ContinueWithAsync)时,事件args与之前的状态相同,因为我不知道如何更新它们。

如何到达e全局并将其设置为新值?我已经尝试通过Variables列表访问它(正如您在代码中看到的那样),但似乎全局变量不会保留在列表中。同时,在运行第一个脚本时,我无法添加任何变量,因为ScriptVariable类具有内部构造函数。 (ScriptState.Variables.Add( ScriptVariable )

感谢您的帮助。我希望我已经表达了自己,一定要在评论中提出任何问题。

1 个答案:

答案 0 :(得分:4)

您可以更新原始e参考:

public class Globals
{
    public int E;
}

static void Main()
{
    var globals = new Globals { E = 1 };
    var _scriptState = CSharpScript.RunAsync("System.Console.WriteLine(E)", globals: globals).Result;
    globals.E = 2;
    var x = _scriptState.ContinueWithAsync("System.Console.WriteLine(E)").Result;
}