一个包装类型提供程序是否应该包含在 class 中具有副作用的值?

Should one wrap type providers containing values that have side effects inside a class?

我正在尝试在我的代码中实施F# coding conventions页面

中的极好的建议

https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/conventions.

Use classes to contain values that have side effects 部分特别有趣。它说

There are many times when initializing a value can have side effects, such as instantiating a context to a database or other remote resource. It is tempting to initialize such things in a module and use it in subsequent functions.

并提供了一个例子。然后它指出了这种做法的三个问题(我省略了缺少 space 的问题,但可以在链接文章中看到它们)并建议使用简单的 class 来保存依赖项。

我想知道应该如何对待类型提供者?例如,如果我有以下代码,

[<Literal>]
let projDataPath = __SOURCE_DIRECTORY__ + @"\data\"

[<Literal>]
let configPath = projDataPath + "config.json"

type Cnfg = JsonProvider<Sample=configPath>
let config = Cnfg.Load(configPath)

使用类型提供程序初始化一个值是否会遇到本文所述的具有副作用的值初始化相关问题?

换句话说,我应该将类型提供程序包装在 class 中吗?

您通常根本不应向消费者公开类型提供者或其提供的类型的实例。除了可能由非 F# .NET 使用者引起的潜在互操作性问题之外,类型提供程序的实例通常代表您的应用程序正在管理的某些私有状态或资源的接口。作为一般规则,最好从您的消费者那里抽象出底层资源,并提供一个最适合问题领域的模型。

链接的文章特别警告不要将具有有限生命周期的 classes 的实例捕获为模块中的绑定,因为绑定是不可变的,并且实例在其生命周期结束时将变得无效。这相当于在 C# class 中将 DbContext 或类似实例作为 static readonly 成员。它将由静态构造函数初始化,但永远不会改变,即使数据库连接关闭并且 DbContext 实例不再有用。