Show/Hide Toolbars

XSharp

Navigation: X# 文档

X# 脚本

Scroll Prev Top Next More

 

以下是尼科斯在科隆举行的 XBase.Future 2017 会议上的演讲内容。

 

本次会议的示例在安装 X# 时保存在 c:\Users\Public\Documents\XSharp\Scripting 文件夹中。

 

为什么要支持脚本?

运行时的动态特性

o可扩展性和灵活性

o用户自定义行为

平台的独立性

o在脚本中定义的系统操作

行为即数据

o存储在文件、数据库和云端

o运行时更新

快速原型设计

脚本是...

表达式评估

o内置解释器

o自带功能

o简单表达或完整陈述

无项目的源文件

o单个文件(单个脚本可加载多个数据源)

o无需完整的集成开发环境或 SDK

o无需集成开发环境的动态编译

o复杂结构、类的定义

作为脚本语言的 X#

Roslyn 脚本引擎

oC# 脚本

独立表达式

o无 START 函数

o全局语句、表达式

o与宏编译器类似(但并不相同!)。

o主机对象维持状态

作为脚本语言的 X#

允许使用复杂的声明

o可以声明类型、函数

o没有命名空间!

外部引用

o加载组件

o无法隐式访问主机程序集

o无隔离(例如单独的 AppDomain)

X-Sharp 解释器 (xsi.exe)

读取-评估-打印循环 (REPL)

控制台应用程序

返回值将打印到控制台

o具有漂亮的格式!

保持上下文

声明局部变量

X-Sharp 解释器 (xsi.exe)

可加载程序集和脚本文件

o.PRGX 扩展

o#R 指令

o#LOAD 指令

可从命令行运行脚本

oXsi.exe <script.prgx>

向脚本传递命令行参数

oXsi.exe <script.prgx> <arg> ...

运行脚本的其他方法

将 xsi.exe 设置为 .prgx 的默认应用程序

o也会创建文件关联,但没有参数

o编辑注册表中的文件关联

手动设置文件关联

oassoc, ftype

调用时不使用 .prgx 扩展名

oPATHEXT

不在控制台运行?

o无法使用 xsi.exe,因为它是一个控制台应用程序

脚本内核:子任务(submission)

每个脚本都被编译为“子任务”

oRoslyn 术语

在 xsi 提示符下输入的每一行都会创建一个新的子任务

o继承之前提交的子任务

o之前已声明的变量仍然可见

不能直接检查

o“SELF“ 和 ”SUPER" 无法访问

脚本内部结构:全局对象

语句在全局对象上下文中执行

由 xsi.exe 生成

oInteractiveScriptGlobals 类

提供对命令行参数的访问

带有漂亮格式选项的打印功能

脚本内核:脚本声明

脚本中声明的 LOCAL 真的是局部的吗?

o在方法之外声明时则不会

o它们会成为 submission 类的字段

那么 FUNCTION 和 PROCEDURE 呢?

o它们会成为 submission 类的方法

声明类型?(类型、结构、枚举)

o它们会成为 submission 类的嵌套类型

o不能有扩展方法!

应用程序脚本:第一步

为您的应用程序添加脚本功能!

引用脚本托管和代码分析程序集

oXSharp.CodeAnalysis.dll

oXSharp.Scripting.dll

重要的命名空间

oLanguageService.CodeAnalysis.Scripting

oLanguageService.CodeAnalysis.Xsharp.Scripting

运行脚本

oXSharpScript.RunAsync("? 'HELLO'")

o如果源代码有错误,会抛出 CompilationErrorException(编译错误异常)。

问题:如何向脚本传递参数?

传递参数:globals 对象

脚本可以访问 globals 对象的 public 成员

oglobals 对象的类型可以是自定义的

可以将 globals 对象的实例传递给 RunAsync()

oglobals 对象的 public 字段可用于向脚本传递参数

o脚本将把它们作为变量来访问

问题:如何为脚本提供 API?

Script API: globals 对象

脚本可访问 globals 对象的 public 成员

o切记:脚本是在内存中的不同程序集中编译和执行的!

提供类型访问权限的方法并不优雅

o但对于基于函数的 API 来说,这一点非常出色

o自成一体(Self-contained)、不易出错

脚本无法直接访问所有应用程序类型

不是安全措施!

o脚本在同一  AppDomain(动态程序集)中运行

Script API: 使用通用组件

脚本可以引用程序集

o通过 #R 指令

o通过传递给 RunAsync() 调用的选项

将脚本可访问的函数和类型移至单独的程序集

o然后脚本就可以引用该程序集了

可与 globals 对象结合使用

问题:如何从脚本返回结果?

Script 结果: 返回值

脚本可以使用 RETURN 语句返回值

o...或独立表达式!

oEvalAsync() 返回该值

oRunAsync() 返回一个 ScriptState 对象,也可以从中获取返回值

Script 结果: 检查脚本状态

可以检查脚本声明的变量

oRunAsync() 返回的 ScriptState 对象包含用于检查变量的方法

ScriptState.GetVariable(string name)

高级主题:处理错误

编译错误

o抛出 CompilationErrorException

oRoslyn API 提供对编译信息的访问

o使用 XsharpScript.Create() 创建 script 对象

o使用 script:Compile() 进行编译

返回诊断信息列表

运行时错误

o抛出异常

因为脚本是作为任务(Task)运行的,所以会出现 AggregateException 异常

e:InnerException 属性包含真正的异常

高级主题:强类型返回值

默认情况下,脚本会返回 OBJECT

可指定自定义返回类型

oCreate<T>()

oRunAsync<T>()

oEvaluateAsync<T>()

高级主题:性能调整

预编译脚本

oScript:Compile()

o编译后的脚本可多次运行

o与宏类似

可使用 script:CreateDelegate() 创建委托

使用 ngen.exe 生成本地图像

o加快初次编译

o64 位 CLR 必须使用 64 位版本的 ngen!!!

o适用于命令行脚本 (xsi.exe)

高级主题:功能脚本

脚本不能像函数一样使用

o不接受参数

相反,它需要一个全局对象实例

o通过脚本托管对象运行

额外开销

但脚本可以对函数进行求值!

oLamda 函数或委托作为返回类型

高级主题:访问应用程序

提供内存中当前程序集的引用

oAssembly.GetExecutingAssembly()

o不能与 CoreCLR 一起使用

可使用当前程序集中声明的实体

oFunctions & procedures

o类型(类、结构等)

o命名空间

高级主题:支持动态

需要引用适当的程序集

oMicrosoft.Csharp.dll