# .NET 互操作

## 命名空间与泛型

只需 `import DocumentFormat.OpenXml;`，随后通过 `DocumentFormat.OpenXml.Packaging`、`Wordprocessing`、`Spreadsheet`、`Presentation`、`Validation` 等访问原生 SDK。不要为这些 .NET 命名空间分别编造 aardio 的 `import` 路径。

C# 的 `obj.Method<T>(args)` 在 aardio 中可写成 `obj.$Method(T)(args)`：第一次调用绑定泛型类型，第二次传实际参数。例如已有 `workbookPart` 时：`workbookPart.$AddNewPart(ox.Packaging.WorksheetPart)()`。

- 子元素批量追加可用 `node.Append([child1,child2])`，不必为此引入泛型 `AppendChild<T>`。
- 属性要求 SDK 值类型时显式构造，例如 `sheet.SheetId = ox.UInt32Value(1)`；读取简单值可取其 `.Value`。
- 传真实的 .NET 类型对象或 SDK 枚举/值常量，不要照搬 C# 的对象初始化器与隐式转换语法。

## 集合与延迟迭代

`dotNet.each` 可直接遍历 SDK 的 `ChildElements` 及验证错误集合。**但不能假定每个 `IEnumerable<T>` 都能直接枚举**：本 SDK 的 `Descendants()` / `Descendants<T>()` 返回编译器生成的迭代器，直接用 `dotNet.each` 可能报找不到 `GetEnumerator`。无需改库，先经 LINQ `ToArray<T>` 转为数组即可：

```aardio
import DocumentFormat.OpenXml;
dotNet.import("System.Linq","System.Core");
var ox = DocumentFormat.OpenXml;

var paragraph = ox.Wordprocessing.Paragraph();
var run = ox.Wordprocessing.Run();
run.Append([ox.Wordprocessing.Text("A"), ox.Wordprocessing.Text("B")]);
paragraph.Append([run]);

// $ 符号开头的方法用于实例化 .NET 泛型类或泛型函数（参数指定 .NET 类型或类型名）
var descendants = paragraph.$Descendants(ox.Wordprocessing.Text)();
var toArray = System.Linq.Enumerable.$ToArray(ox.Wordprocessing.Text);
var texts = [];
for i,node in dotNet.each(toArray(descendants)) table.push(texts,node.Text);
return texts; // ["A","B"]
```

`ToArray` 会实体化整个序列；巨型文件不要据此构造多个全量副本，应另行采用 SDK 的流式读取或受控遍历。DOM/SDK 对象不当作可跨线程共享的 aardio 普通表。

## 文件、流与保存

- `Open` 默认只读，修改文件须传 `true`。仅在内存修改 DOM 不代表文件已保存。
- `Create` 的第三参、`OpenSettings.AutoSave` 都可控制自动保存。`AutoSave=false` 不是事务回滚；显式保存和包级操作的影响须按 SDK 语义处理。需要回滚时编辑副本。
- 要传入设置：创建 `ox.Packaging.OpenSettings()`，设置其属性，再调用 `DocumentClass.Open(path, false, settings)`。
- 将 `AutoSave` 设为 false 后，不要期待仅 `Dispose()` 就保存 DOM 修改；必要时调用对应根元素的 `Save()`。
- 调用方创建的流保持到文档 `Dispose()` 完成后再释放。重读内存流前设 `Position=0`。传入的流应满足 SDK 所需的读写与定位能力；写包宜用可扩展的 `System.IO.MemoryStream()`。
- SDK 3.x 用 `Dispose()` 关闭文档，不照搬旧版示例中的 `Close()`。

## 运行时与版本

本扩展库固定内嵌 OpenXML SDK 3.5.1 的 net35 资源，内存加载程序集而不是在运行时下载 SDK。`dotNet` 默认优先尝试 CLR 4，再尝试 CLR 2；当前资源已在 CLR 4 环境验证。Windows 7 开始已自带 net35，这表示除了已被市场淘汰的古老 Windows XP，所有 Windows 都已直接支持此扩展库，无需额外安装 .NET Framewordk 。

修改库或切换程序集后用干净线程重新导入，避免缓存混用；同一工作流不要另加载不同版本的  SDK OpenXML DLL。

## 上游资料

仅在需要相关 API 时查阅，注意筛选 SDK 3.x 和实际目标框架；例如 net35 不提供带 `CancellationToken` 的公开验证重载。

- [Microsoft Learn：Open XML SDK](https://learn.microsoft.com/office/open-xml/open-xml-sdk)
- [SDK 源码](https://github.com/dotnet/Open-XML-SDK)
- [3.5.1 对应源码提交](https://github.com/dotnet/Open-XML-SDK/tree/3139fdfd27414548a41555f7848d5728f6e71a42)
- [NuGet：DocumentFormat.OpenXml 3.5.1](https://www.nuget.org/packages/DocumentFormat.OpenXml/3.5.1)

本地库参考刻意不展开全量 SDK 成员，避免 AI 为简单任务载入无关上下文。
