将对象实例传递给Roslyn ScriptEngine

本文关键字:Roslyn ScriptEngine 对象 实例 | 更新日期: 2023-09-27 18:12:41

我正在寻找一个c#脚本引擎,它可以解释c#代码块,同时保持上下文。例如:输入:var a = 1;,再输入a + 3,则输出4。我知道MS Roslyn确实做到了这一点,但它是一个沙盒(关于启动它的程序)。因此,如果我创建一个ScriptEngine的实例和一个MyClass的实例(只是我的一个任意类),我没有选择将my_class的引用传递给script_engine

是否有可能以某种方式传递引用?

我想做的是:

ScriptEngine engine; // A Roslyn object
Session session // A Roslyn object
MyClass my_class; // My object
// all required initializations
Submission<object> sm = session.CompileSubmission<object>("var a=1;"); 
dynamic result = sm.Execute(); 
Submission<object> sm = session.CompileSubmission<object>("a + 3;"); 
dynamic result = sm.Execute(); // result is now 4
MyClass my_class;
session.AddReferenceToAnOject(my_class); // function that does not exists, but reflect my intention
Submission<object> sm = session.CompileSubmission<object>("my_class.ToString();"); 
dynamic result = sm.Execute();  // result is no the output of my_class.ToString()

请注意AddReferenceToAnOject()是缺失的部分,因为roslyn中没有这个功能。

将对象实例传递给Roslyn ScriptEngine

答案是在@Herman评论的链接中找到的。

事实证明,Roslyn ScriptEngine/Session支持Host Object的概念。为了使用它,定义一个您选择的类,并在会话创建时传递它。这样做,使该宿主对象的所有公共成员可用于会话内的上下文:

public class MyHostObject
{
    public List<int> list_of_ints;
    public int an_int = 23;
}
var hostObject = new MyHostObject();
hostObject.list_of_ints = new List<int>();
hostObject.list_of_ints.Add(2);
var engine = new ScriptEngine(new[] { hostObject.GetType().Assembly.Location });
// passing reference to hostObject upon session creation
var session = Session.Create(hostObject);
// prints `24` to console
engine.Execute(@"System.Console.WriteLine(an_int + list_of_ints.Count);", 
               session); 

这是一个完整的过程如何传递变量从对象到roslyn动态执行的代码。还包括eval()包装器。首先从microsoft.com http://www.microsoft.com/en-sa/download/details.aspx?id=34685安装RoslynSetup.exe

然后添加参考Roslyn。编译器和Roslyn.Compilers.CSharp到你的项目(程序集/扩展)

这是vs2012中c#控制台应用程序的完整工作代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;
using Roslyn.Scripting;
using Roslyn.Scripting.CSharp;
namespace testRoslyn
{
    class Program
    {
        static void Main(string[] args)
        {
            TestRoslyn tr = new TestRoslyn();
            tr.Test = "this was set from main program ";
            tr.test();
            System.Console.WriteLine(tr.Test);
            tr.Test = "this was set from main program for eval";
            Eval e = new Eval();
            e.create<TestRoslyn>(tr);                           
            e.eval("Test = Test + '" AND THIS WAS SET FROM Eval()'";");
            System.Console.WriteLine(tr.Test);
            string a = e.eval<string>("string a = '"return this from eval'";a");
            System.Console.WriteLine(a);
            tr.Test = "now return this";
            string b = e.eval<string>("string a = Test + '" ... and this'";a");
            System.Console.WriteLine(b);
            double d = e.eval<double>("double dbl = 1.2345*3;dbl");
            System.Console.WriteLine(d);
            e.eval("string testIt(string a){return '"testIt(): '"+a+'"'";}");
            string c = e.eval<string>("string c = testIt('"nice'");c");
            System.Console.WriteLine(c);
            Console.ReadKey();
        }
    }
    public class TestRoslyn
    {
        public string Test;
        public TestRoslyn()
        {
        }
        public string test()
        {
            ScriptEngine roslynEngine = new ScriptEngine();
            Roslyn.Scripting.Session session = roslynEngine.CreateSession(this);
            session.AddReference(this.GetType().Assembly);
            session.AddReference("System.Web");
            session.ImportNamespace("System");
            session.ImportNamespace("System.Web");
            var result = (string)session.Execute("Test = Test + '" ... and this was set from roslyn code.'";Test");
            return result;
        }
    }
    public class Eval
    {
        ScriptEngine RoslynEngine = new ScriptEngine();
        Roslyn.Scripting.Session Session;
        public void create<T>(T hostObject = null) where T : class
        {
            RoslynEngine = new ScriptEngine();
            Session = RoslynEngine.CreateSession(hostObject);
            if (hostObject != null)
                Session.AddReference(hostObject.GetType().Assembly);
            Session.AddReference("System.Web");
            Session.ImportNamespace("System");
            Session.ImportNamespace("System.Web");
        }
        public void eval (string strEval)
        {                                                
            Session.Execute(strEval);
        }
        public T eval<T>(string strEval) 
        {
            return (T) Session.Execute(strEval);            
        }
    }
}