【发布时间】:2012-10-17 14:36:22
【问题描述】:
是否可以在 F# 中定义包含可重载成员的静态类? let 模块绑定不能被重载,即使它们被编译成静态类中的静态静态成员。
type declerations 可以包含静态成员,但不知道是否可以将类型本身设为静态。
我目前的解决方案是使用私有构造函数定义 type 并使用它。我想知道是否有一种方法可以根据需要定义静态类型。
【问题讨论】:
是否可以在 F# 中定义包含可重载成员的静态类? let 模块绑定不能被重载,即使它们被编译成静态类中的静态静态成员。
type declerations 可以包含静态成员,但不知道是否可以将类型本身设为静态。
我目前的解决方案是使用私有构造函数定义 type 并使用它。我想知道是否有一种方法可以根据需要定义静态类型。
【问题讨论】:
The F# Component Design Guidelines 对此进行了解释。
[<AbstractClass; Sealed>]
type Demo =
static member World = "World"
static member Hello() = Demo.Hello(Demo.World)
static member Hello(name: string) = sprintf "Hello %s!" name
let s1 = Demo.Hello()
let s2 = Demo.Hello("F#")
仍然可以定义实例方法,但是在没有可用的构造函数时不能实例化类。
编辑 2021 年 1 月:查看 Abel 的评论和链接的问题。 Joel Mueller 的回答似乎是迄今为止最好的建议,但未来情况可能会发生变化。
【讨论】:
let foo = new Demo()
public static class Demo { ...。省略 AbstractClass 会导致它不是是一个静态类。如果您正在与另一种语言进行互操作,这可能会更明显。
AbstractClass 属性。另请参阅此错误报告:github.com/dotnet/fsharp/issues/8093
正如 Robert Jeppeson 所指出的,C# 中的“静态类”只是创建一个无法实例化或继承自且只有静态成员的类的简写形式。以下是在 F# 中实现这一点的方法:
[<AbstractClass; Sealed>]
type MyStaticClass private () =
static member SomeStaticMethod(a, b, c) =
(a + b + c)
static member SomeStaticMethod(a, b, c, d) =
(a + b + c + d)
这可能有点矫枉过正,因为AbstractClass 和私有构造函数都会阻止您创建该类的实例,但是,这就是 C# 静态类所做的 - 它们被编译为抽象类带有私有构造函数。 Sealed 属性阻止您从此类继承。
如果您像在 C# 中那样添加实例方法,这种技术不会导致编译器错误,但从调用者的角度来看没有区别。
【讨论】:
AbstractClass 和 Sealed,否则 C# 不会这样看(另请参阅此错误报告:github.com/dotnet/fsharp/issues/8093)。
我认为这里的问题是试图将 F# 变成 C#。如果问题不能以非命令方式解决,请使用 C# 或编写面向对象的库并在 F# 中使用。
【讨论】:
我不确定是否存在静态类。我相信,C# 中类级别的“静态”是在 2.0 中引入的,主要是为了方便(避免私有构造函数和编译时检查不存在实例成员)。您无法检查类型并得出结论它是静态的:http://msdn.microsoft.com/en-us/library/system.reflection.typeinfo.aspx
更新: MSDN 声明一个静态类是一个密封的并且只有静态成员的类: http://msdn.microsoft.com/en-us/library/79b3xss3(v=vs.80).aspx
所以,你现在正在做的就是做它的方法。
【讨论】:
在 F# 中没有定义 static 类型的工具。
第一种选择是定义一个模块,但它缺乏重载函数的能力(这是你所追求的)。第二种选择是用静态成员声明一个普通类型。
关于第二种方法,这正是 the accepted answer 对您的旧问题所描述的。我重构了代码以更容易地解释它。首先,定义了一个虚拟的单案例可区分联合:
type Overloads = Overloads
其次,利用静态成员可以重载的事实:
type Overloads with
static member ($) (Overloads, m1: #IMeasurable) = fun (m2: #IMeasurable) -> m1.Measure + m2.Measure
static member ($) (Overloads, m1: int) = fun (m2: #IMeasurable) -> m1 + m2.Measure
第三,使用inline关键字将这些重载方法的约束传播到let-bounds:
let inline ( |+| ) m1 m2 = (Overloads $ m1) m2
当您能够使用此方法重载 let-bounds 时,您应该创建一个包装模块来保存这些函数并标记您的类型 private。
【讨论】:
Overloads 的工会成员的访问,但这仍然会非常复杂。
type Overloads = private | Overloads。静态类在 F# 中并不是真正有用,除了重载目的。我认为你最好的选择是使用私有构造函数。