我需要调用类before
的静态成员调用类构造函数。该类实现接口,我需要(以多态)在after the object is constructed
上(polymorthy)拨打同一静态成员。
我相信某些语言允许一种语言在点之前使用实例名称访问静态方法,例如
myClassInstance.staticMethod
f#似乎不允许这样做,尤其是当类从接口继承的情况下,因为接口不能包含静态方法。
以下代码例证了问题:
module Types
type IMult =
abstract member Something : float
abstract member MultBy : float -> float
open Types
type Point(x: float) =
interface Types.IMult with
member this.Something with get() = x
member this.MultBy (x: float) =
(this :> IMult).Something * x
static member public foo x = x + 3.0
let myPointConstructorArgument = Point.foo 5.0
let pt = Point(myPointConstructorArgument)
printfn "%f" <| (pt :> IMult).MultBy 10.0 // OK: 80.0
let bar (instnc: IMult) = instnc.foo // Error: foo not defined
let pt0 = Point(bar pt 6.0) // No good: error above
我的问题是:是否可以以某种方式检索对象的类,然后调用抽象方法?
我尝试了以下内容:
let ptType = pt0.GetType()
let mtd = ptType.foo // Error: foo not defined
let mtd = ptType.GetMethod("foo") // Ok, but not what I need, see below
let i2 = mtd 3.0 // Error: mtd is not a function
有关此操作的替代方法的任何建议?
听起来您真正想要的是"类型类"或"证人",这是尚不支持的语言功能,但是此问题,跟踪该功能的实现非常活跃。
目前在F#中有几种获得您想要的多态性访问的方法。
1)通过接口实例成员。看来您不能将多态构件直接放在IMult
类型上,因为您需要在构造实例之前访问它,但是您可以为"类型" 创建界面,然后将其传递给作为另一个参数(这与类型类在"封面下"的工作非常相似):
//your "trait"
type IFoo<'a> =
abstract member Foo : float -> float
//your "witness", defines what "Foo" means for the "Point" type. Other witnesses could define what "Foo" means for other types.
let fooablePoint = { new IFoo<Point> with member this.Foo x = Point.foo x }
let bar (fooable:IFoo<'a>) = fooable.Foo //this isn't really necessary anymore, but illustrates that a function can use a polymorphic "static" function, given a witness
let pt0 = Point(bar fooablePoint 6.0)
2)静态成员约束(如上所述所指出):
let inline bar (pt:^a) x =
(^a : (static member foo : float -> float) x)
一方面,这使您能够在类型上访问静态成员,尽管不应根据fsharp.org过度使用它。它的语法非常不透明,很难破译。此外,它仅适用于内联函数,因此,如果使用普遍存在,可能会大大破坏应用程序的性能。请注意,这也只有在您已经具有^a
类型的实例时才有效,因此此解决方案也可能对您不起作用。
3)只需将foo函数传递到其他需要的其他功能中:
let bar (foo:float -> float) x = foo x // type annotations wouldn't be necessary, and just provided for clarity
let pt0 = Point (bar Point.foo 6.0)
4)(在下面的评论中讨论):内部IMult
您仍然可以定义
abstract member foo: float -> float
然后在Point
中,只有
interface Types.IMult with
member this.Foo x = Point.foo x
这可能会给您您想要的一切。然后,该成员将在Point
类型( and IMult
上的实例成员)上以静态成员的形式存在,因此它不再是"静态多态性",但它可能会实现您的目标。
我会选择上面的" 1",不要挂在类型的类别上 - 它们不存在,在某些方面,它们并不理想。<<
对我而言,您缺少抽象,将其视为某种工厂或域实体,可以捕获您的静态方法,并只是明确地将其传递。
type MultDomain<'a when 'a :> IMult> =
abstract member foo : float -> float
type PointDomain =
interface MultDomain<Point> with
member o.foo x = x + 3.0
(在您的上下文中不需要约束" a:> imult",但表明您可以在此接口中使用您尚未创建的对象的类型)
所以答案是"是的,只要您将它们映射到某种类型的实例方法,您可以用多态词法调用" ...或者也许"不,但是您可以将它们映射到某种类型的实例方法。
(我个人从来没有静态方法,甚至避免构造函数!)