一、项目背景
CScript: 一个仿照海康 VM 的 C# 脚本编辑器,使用 WPF + Roslyn + AvalonEdit实现。
运行效果:

运行步骤: 加载引用目录 → 在左侧配好输入输出变量 → 在编辑区写脚本 → 补全/参数提示辅助编码 → 点"编译"看诊断 → 点"执行"看输出 → 输出变量表自动刷新出结果。
二、运行环境
| 项目 | 说明 |
|---|---|
| 操作系统 | Windows(WPF 桌面应用,WinExe 输出) |
| 运行时 | .NET Framework 4.6.2 |
| 语言版本 | C# 7.3(统一锁定到 7.3) |
| 界面框架 | WPF(MVVM-lite,实质为代码后置 + 事件驱动) |
| 代码编辑器 | AvalonEdit 6.1.2(行号、语法高亮、折叠、补全窗口) |
| 编译器/分析器 | Microsoft.CodeAnalysis.CSharp.Scripting / CSharp.Features 3.11.0 |
| 网络依赖 | 无。补全、编译、执行全部在本机进程内完成 |
| 部署形态 | 单机绿色运行,适合无外网的工控机、产线调试机 |
关注点: 脚本模块以 Regular 模式解析(允许 namespace、class),因此用户写的是一份结构完整的 C# 源码,而不是"表达式片段"------这一点和 VM 脚本模块的使用习惯是一致的。
四、功能说明
-
Roslyn 智能补全(RoslynCompletionProvider.cs)
用 MEF HostServices + AdhocWorkspace 搭建进程内 Roslyn 工作区
把 Roslyn CompletionItem 映射为自定义 RoslynCompletionItem.cs,支持图标、签名、描述异步加载
提供 GetCompletionsAsync / GetDescriptionAsync 两个对外接口
-
补全交互(CodeEditorControl.xaml.cs)
输入字母或 . 自动触发补全,Ctrl+Space 手动触发
CompletionWindow 展示、Enter/Tab 插入、Esc 关闭、鼠标选中
输入 (` 或,触发参数提示,Escape/)关闭
-
输入变量注入补全 (ScriptVariableInjector.cs)
把输入变量写成 public readonly ; 注入 UserScript 类体,让脚本里能直接写 inValue
单行插入 + 光标偏移修正(不打乱诊断行号)
非法/重复变量名跳过,类型非法回退 object
补全文档与编译产物共用同一套注入逻辑,保证"补全能看见的 == 编译时存在的"
-
参数签名提示 (RoslynCompletionProvider.cs + SimpleOverloadProvider.cs)
因为 Roslyn 3.11 的 SignatureHelpService 是 internal,改用公开 SemanticModel API 兜底:定位调用点 → GetSymbolInfo 取方法符号 → 数逗号定当前参数索引 → 拼签名
通过 AvalonEdit OverloadInsightWindow 展示
-
动态引用管理(ReferenceManager.cs / IReferenceManager.cs)
基础引用(mscorlib、System、System.Core、System.Data、System.Xml、宿主程序集)+ 动态引用分离
ScanDirectory 批量扫描、AddReference / RemoveReference / CanRemove
自动挂载同名 .xml 文档注释,补全项能显示摘要
基础引用设为不可移除,防止误删导致补全引擎失效
-
引用程序集管理窗口 (AssemblyListWindow.xaml)
列表展示名称 / 路径 / 是否有文档 / 是否可移除
➕ 添加引用、➖ 删除选中、右键菜单"删除选中引用"
-
代码折叠 ( RoslynFoldingStrategy.cs)
基于 Roslyn 语法树生成折叠区域,文本变化后延迟刷新
-
脚本编译与执行 (ScriptRunner.cs / ScriptGlobals.cs / ActionTextWriter.cs)
内存编译为程序集 → 反射找到继承 ScriptGlobals 的类 → 反射写入只读输入字段 → 调用 Init / Process
执行期间 Console.Out 重定向到界面输出面板
编译错误按行号格式化输出,支持取消
-
主窗口功能(ScriptEditorWindow.xaml)
导入 / 导出脚本、添加引用目录、引用程序集窗口
输入变量 DataGrid(名称 / 类型 / 值,可增删)
编译 / 执行 / 停止、输出搜索、清空输出
五、分层设计
此项目有二十多个文件,可以按"契约 / 引擎 / 界面"三层来看:
- 契约层:IRoslynCompletionProvider(补全、签名、描述)、IReferenceManager(引用集合与变更事件)、变量与结果模型;
- 引擎层:ReferenceManager(引用收集)、RoslynCompletionProvider(工作区与补全)、ScriptVariableInjector(字段注入,补全与编译共用同一份实现)、ScriptRunner(编译与执行)、ScriptGlobals(宿主基类)、RoslynFoldingStrategy(折叠);
- 界面层:ScriptEditorWindow(主窗与流程编排)、CodeEditorControl(补全窗口、参数窗口、折叠、去抖与单飞)、AssemblyListWindow(引用管理)、RoslynCompletionItem / SimpleOverloadProvider / ActionTextWriter(适配器)。