简体中文
English 简体中文 繁體中文
Methodox 首页

教程——Pure 的基本用法

目录

  1. 库的使用
  2. 实用工具
  3. 高级主题

1. 库的使用

1.1 库的类型

Pure 2 支持从以下来源导入库,优先级如下:

  1. Pure 2 自定义库/代码片段/宏。
  2. (开发中)(Divooka 包):按名称(或通过别名)。
  3. NuGet:按名称。
  4. 特定的 DLL 文件。

语法都是一样的:Import(Library)。在幕后,它会编译所需的 DLL 并自动加载。

有时某些 NuGet 包编译出的 DLL 名称与 NuGet 包名不同。在这种情况下,你可能需要使用 Import(Library as DLLName) 语法。我们希望在未来的更新中自动解决这个问题。

2. 实用工具

2.1 Notebook 程序(目前仅在 Windows 上可用)

除了 Pure.exe 之外,还有一个单独的 Notebook.exe,它提供类似 jupyter notebook 的界面,以便更轻松地进行调试和开发。

Notebook 界面仅可在 Windows 上使用——不过借助跨平台技术,可以很容易地为其他桌面环境开发一个。我没有去做,因为只有我一个人在用 Pure。

警告:请注意,如果你属于以下情况,Pure 并不适合你:1)需要运行和维护不愿采用新 C# 特性的过时代码库;2)对自定义库或遗留代码有很强的依赖;3)只能使用 .Net Framework;4)需要长期固定使用单一运行时版本。在这些情况下,Pure 不适合你,因为 Pure 将始终更新到最新的 .Net 运行时,而在采用新特性时,向后兼容性是最不被优先考虑的因素之一(尽管显然会保证一定程度的“稳定性”)。

3. 高级主题

3.1 创建供 Pure 使用的库

Pure 有三种可直接使用的库:

  • 任何发布在 Nuget 上的常规 C# Net 8 DLL。较旧版本的 .Net Core dll 也可能可以使用,但请谨慎;甚至 .Net Framework dll 也可能可以使用,但我观察到过行为不可预测的情况。
  • 任何可以使用 Include 宏包含的用户编写的脚本。
  • 任何发布在 Central Snippets 或类似地方的用户分享的代码片段。

Pure 的预期使用场景如下:

  • Pure 提供完整的语法以及 .Net 8 运行时(C# 12)的所有标准特性
  • 在基础之上,Pure 提供一些额外的库/代码片段,以进一步简化常见任务
  • 在此之上,Pure 原生支持库导入(使用 Import())和脚本导入(使用 Include())
  • 在扩展 Pure 的现有功能,或仅仅是围绕可复用代码开发库时,开发者会编写真正的 C# 类库项目,并将其以 DLL 形式提供,最终在 Pure 中使用。

因此,为 Pure 创建库非常简单——就像创建任何标准 C# 库一样。默认情况下,在 Pure 中导入时,DLL 模块中所有包含公共类的命名空间都会被导入。

库可以通过遵循以下约定来提供丰富的运行时行为(所有约定都不需要依赖 Pure 2 的运行时),这些约定在使用 Import() 导入时生效:

  1. 当库程序集中提供了名为 Main 的静态类时,它的所有静态成员都将在全局可用;
  2. 如果提供了名为 Pure2LibraryOptions 的静态类,则可以使用几个参数来改变库的加载行为:1)public static bool DefaultNamespaceImport = true 指定是否默认导入所有包含公共类的命名空间;2)public static string[] TopLevelClasses = ["Main"] 指定哪些类应在导入时公开其所有成员,这等同于使用 Main,或作为其替代方案(当我们有多个类希望在全局级别导出名称时很有用)。

故障排除

Pure 使用 Net 8 编写。然而,在加载外部 DLL 时,目前只能安全地假定开箱即用地支持 Net Standard 2.0 以及可能的 Net Core 3.1 上下文(即直接加载 Net 8 dll 可能无法立即工作)。例如,即使平台(如 win64)受支持,System.Data.Odbc 也会抛出“Platform not Supported”异常——导致问题的是运行时。一个临时的变通方法是:在开发插件/库时,所有插件都应以 Net Standard 2.0+、Net Core 3.1+ 或 Net Framework 4.6.1+ 为目标。实际上,问题并不在于作为托管上下文的 Net 8——运行时确实是 8.0.0(在 Roslyn 中),而且 CSharpREPL(我们的参考解释器)可以毫无问题地使用 System.Data.Odbc(在 .Net 7 的情况下),所以我们应该能够加载 Net 8 程序集,只是由于我们处理 DLL 加载的方式,我们需要准确加载正确的 DLL,而不能加载一个“入口” dll。我们可以使用 CSharpREPL 找到所需的正确 DLL(例如,对于以 .Net 7 为目标的 ODBC,它应该是 AppData\Roaming\.csharprepl\packages\System.Data.Odbc.7.0.0\runtimes\win\lib\net7.0\System.Data.Odbc.dll)。在实践中,查看临时的 dotnet 构建解决方案时,可以在 runtimes 文件夹下找到特定的 dll。

System.Drawing 在此平台上不(直接)受支持。请注意,使用 ODBC 库时也是这种情况——可能是因为它有许多运行时版本。这是因为目前“Import”无法正确利用那些可能用于重定向的 dll。一种解决方案是在构建时选择特定的运行时,而不是以“Portable”运行时为目标。在尝试导入模块时,Pure 会就此类情况通知用户。

库编写要求:请注意,任何正在编写的(插件)库都不能(因此也不应该)直接(或间接)以 .Net 8 Windows 为目标,因为托管环境(即 Pure)的目标是 .Net 8(未指定 Windows 作为目标)。解决方案是将此类组件隔离出来,并作为子进程触发(因此需要某种数据传输或 IPC)。

3.2 Visual Studio 开发(完整 C# 项目)

对于快速、迭代、按需的开发,建议使用上文 2.1 节中介绍的 Notebook 程序。

对于稍微复杂一些的脚本,可以使用 Visual Studio 进行调试。(对于更高级的应用,建议使用正式的 C#)。请注意,建议将所有内容保存在单个文件中,并且不要将 csproj 和 sln 文件提交到版本控制。

使用 .Net 8 创建一个 C# 控制台项目,同时确保关闭 Do not use top level statements(不使用顶级语句)选项。(如果使用命令行,也可以直接在脚本文件夹中执行 dotnet new console)

VSDevSetup_Step1 VSDevSetup_Step2

如果你不想处理 null 值,可以选择在 .csproj 文件中指定 <Nullable>disable</Nullable>,如下所示:

VSDevSetup_Step3

要在此环境中引用 Pure 库,只需将 Nuget 源设置为指向 Pure 的安装文件夹,其中包含一个存放 Nuget 包的文件夹。

VSDevSetup_Step4

之后,安装包的方式与任何其他 C# 项目一样。

VSDevSetup_Step5

完成此设置后,你就可以直接在 Visual Studio 中编写和调试 Pure 脚本:

VSDevSetup_Step6

请注意以下几个显著区别:

  1. 你将无法使用 Import,它会自动查找库并设置静态 using。
  2. C# 顶级语句要求类型定义(例如 record)位于所有其他函数和语句的底部,而在 Pure 中可以放在任何位置。
  3. 你需要显式声明 using static System.Console; 才能将这些名称公开到文件作用域,而在 Pure 中这是自动完成的。

以下是完整的脚本:

// Notice `Import(PackageName)` macro is only available in Pure
Import(ODBC)
using static System.Console;
using static ODBC.Main;

DSN = "SQLITE";
Row[] rows = Select<Row>("""
    SELECT *
    FROM MyTable
    """);
foreach (var row in rows)
    WriteLine(row.Name);
public record Row(string Name, double Value);

将 C# 项目转换为 Pure 脚本时,请注意以下区别:

// Import(ODBC)

using static System.Console;
using static ODBC.Main;

// Include(MyScript.cs)
string[] Arguments = new string[] { "--help" };

其中:

  1. Import() 和 Include() 不起作用,但可以使用 Nuget 和项目文件达到同样的效果。
  2. 在 C# 和 Pure 中,using 语句都必须位于脚本顶部。
  3. 需要定义一个辅助的 string[] Arguments,否则它由 Pure 提供。

另有一段视频介绍了如何将 Pure 脚本转换为 C# 项目。