序列化.NET Roslyn中的ScriptState<T>
本文共664字。
版权声明:署名-非商业性使用-相同方式共享
|
CC BY-NC-SA 2.5 CN
放弃了, 没找到解决方案
本文内容存在错误,正在等待修复
ScriptState<T>
是.NET
的Roslyn
中用于储存脚本运行结果的对象。ScriptState
中只暴露了少部分内容,所以不能通过直接使用System.Text.Json.JsonSerializer
或XML等进行序列化。
如果使用自定义派生类的方式进行Json或XML序列化,需要大量Dirty work。
思路
这时候不妨回顾一下序列化的定义:
序列化(serialization)在计算机科学的资料处理中,是指将数据结构或对象状态转换成可取用格式(例如存成文件,存于缓冲,或经由网络中发送),以留待后续在相同或另一台计算机环境中,能恢复原先状态的过程。
–Wikipedia
所以实际上没有必要把目光局限在Json或者XML等格式,序列化ScriptState
当然只需要把Script
存储下来即可。
问题
笔者的场景是一个类似于csi.exe
的交互式脚本shell
,用户会在脚本中输入如return 0;
或者表达式a+b
,函数调用func(arg);
的代码:如果直接拼接用户输入,保存并在反序列化时重放会出现问题如:
- 代码被
return;
阻断,return;
后面代码参与的上下文无法被反序列化。 - 密集计算函数
func(arg)
被重复调用,有时候这些函数的结果并不存储在上下文中,导致反序列化时间过长。
解决这些问题的方法其实非常明了,只需要把脚本中的这些部分去除即可。
解决方案
造成以上问题的语句看似(待验证)只有以上两种语句,也即
return;
expression
Roslyn
提供了许多非常方便的功能,比如我们可以通过直接读取语法树,知道代码中包含什么内容。
1 | Compilation compilation = newScript.GetCompilation(); |
这两种无值的、需要筛除的语句都是顶级语句,所以我们可以先筛选出语法树中的顶级语句:
1 | var globalStatements = syntaxNodeRoot.ChildNodes() |
然后我们可以从中进一步筛选出返回和表达式:
1 | var returnAndExpressionStatements = globalStatements |
这样我们就得到了需要筛除的所有Statement
。
Statement
对象的Span
属性标记了该对象在源代码中的具体位置,非常方便我们进行筛除:
1 | var processedCode = rawCode; |
这样就大功告成了。