以下(简化)代码段取自我正在实现的应用程序,该应用程序始终使用静态解析的类型参数 .
type A< ^B when ^B : (static member MyMember : Unit -> Unit)> = {
Field : unit
}
type TestA = {
AField : A< BTy >
}
and BTy = {
BField : Unit
} with
static member MyMember () = ()
当我定义字段AField( AField : A< BTy >
)的类型时,IntelliSense给出了以下错误: The type 'BTy' does not support any operators named 'MyMember' .
编辑 . 单独声明它们是有效的,但是如果我有一个共同引用并且我声明第三种类型放在顶部,它包含两种类型的公共信息 . 我该怎么做才能避免这个问题?无论如何,如果我定义下面的定义 let pluto = ("" :> obj) :?> A< BTy >
它有效,我想是因为这两种类型都可以从let绑定中看到 .
2 回答
说实话,我有点惊讶你甚至被允许在类型声明中使用静态成员约束,但正如@pad所提到的,当你按正确的顺序放置声明并删除递归时,它有效(尽管当你转向更复杂的例子时,我不确定是否会有其他限制):
无论如何,我认为在类型声明中使用静态成员约束有点复杂 . 更简洁的方法是定义一个清晰描述(和文档)所需成员的界面:
现在,静态成员约束仍可用于从具有所需成员的类型创建接口的实现,但不实现接口 . 使用这种技术,您应该能够实现与对类型的静态成员约束完全相同的功能(但以更清晰的方式):
例如,该函数将从
BTy
类型创建IMyMember
:除此之外,我在一篇文章中使用了相同的技术,该文章展示了如何write generic numeric code,我认为它在那里非常好用 .
你的实现@Tomas满足了这个问题,但是你对解决方案的风格有些犹豫,因为它不尊重函数式编程范式 . 我想到了一个由Haskell的Type Classes实现产生的解决方案 . 已经实现了接口,抽象类等,以便允许F#环境与.Net环境“交互”,原因是样式的一致性使用在上下文中实现接口,抽象类等的代码 . 不需要与.Net库交互,在我看来它是一个“开销”(尽管F#是一种多范式语言) . 这就是为什么我发现Haskell类型类的实现非常优雅的原因 . 下面我通过F#实现了“Haskell Type Class”代码来解决我的问题 .