将对象实例传递给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中没有这个功能。
答案是在@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);
}
}
}