用c#解析.ipynb文件需以utf-8读取json并反序列化为poco,提取code cell的source数组拼接为字符串,跳过空cell;不可直接执行,因缺少notebook运行时上下文。

如何用 C# 解析 .ipynb 文件的 JSON 结构
IPython Notebook(.ipynb)本质是 UTF-8 编码的 JSON 文件,C# 读取它不需要专用库,但必须正确处理 JSON schema 和编码边界。直接用 File.ReadAllText 读取再反序列化是最稳的路径。
- 务必指定
Encoding.UTF8,否则含中文或 emoji 的 cell 会乱码(File.ReadAllText(path)默认用系统编码,Windows 上常是 GBK) - 推荐用
System.Text.Json(.NET 5+),别用Newtonsoft.Json—— 后者对metadata中未定义字段易抛异常,而.ipynb的metadata字段版本差异大(如 JupyterLab vs classic)、常含扩展键 - 关键结构:根对象有
cells数组,每个cell有cell_type("code"/"markdown"/"raw")、source(字符串数组,每行一项)和可选的execution_count
var json = File.ReadAllText(path, Encoding.UTF8); var nb = JsonSerializer.Deserialize<Notebook>(json); // Notebook 是你定义的 POCO
提取并拼接 code cell 中的 C# 代码片段
注意:.ipynb 本身不绑定语言,C# 代码只是普通文本;所谓“C# Notebook”实际依赖 dotnet-interactive 内核,文件里不会标记语言——metadata.kernelspec.language 是 "dotnet-csharp" 或 "csharp",但不可靠;真正要执行的代码全在 cell.source 里。
-
source是string[],不是单个字符串,需用string.Join("\n", cell.source)拼接,否则换行丢失 - 跳过空 cell 或只有注释的 cell:检查
cell.source.All(s => string.IsNullOrWhiteSpace(s)) - 不要自动添加
using或class Program—— dotnet-interactive 执行的是表达式/语句上下文,不是完整编译单元;强行包裹反而导致编译失败 - 若需模拟执行环境,得自己维护变量作用域(比如用
ScriptState+CSharpScript),但这已超出解析范畴
为什么不能直接用 C# 执行 .ipynb 里的代码
因为执行 ≠ 解析。C# 没有内置 notebook 运行时,Microsoft.DotNet.Interactive 是唯一正统方案,但它不是“加载文件后 run 一下”就能用的库。
-
DotNetInteractive设计为进程内服务(Kernel实例),启动需初始化KernelInvocationContext、注册SubmissionLoader等,不是调个函数的事 - 它不接受 raw JSON 或
cells列表作为输入,只认IKernel流程:解析 → 创建 submission → 推入 execution queue → 返回KernelEvent - 常见误操作:试图把
source字符串喂给CSharpScript.EvaluateAsync—— 会失败,因缺少 notebook 特有的上下文(如#r "nuget:..."、#i "path"、%%time魔法命令)
实际可行的轻量级方案:导出为 .cs 文件再编译
如果目标只是“让 C# 代码跑起来”,绕过 notebook 运行时更可靠。Jupyter 自带导出功能,但要用代码自动化就得调 CLI 或解析后手动生成。
- 用
jupyter nbconvert --to csharp input.ipynb命令(需装 jupyter 和 dotnet-interactive)—— 但依赖 Python 环境,不适合纯 C# 项目 - 更可控的做法:遍历所有
cell_type == "code"的 cell,拼接source,头尾加上using static System.Console;和空Main方法壳(仅用于快速验证),写入.cs文件,再用CSharpCompilation编译执行 - 注意魔法命令:遇到
#r或#i行,不能忽略——它们影响引用和搜索路径,需提取后传给编译器的MetadataReference或SourceReference
最麻烦的永远不是读取,而是处理 notebook 特有的执行契约:状态延续、输出捕获、富媒体返回。真要嵌入 notebook 执行能力,得接受它是个 mini runtime,不是个文件格式。










