我可以多态访问静态方法吗?

时间:2017-09-23 20:22:23

标签: static f# polymorphism

我需要调用类before的静态成员来调用类构造函数。该类实现了一个接口,我需要稍后在after the object is constructed上调用(多态)相同的静态成员。

我相信有些语言允许用户在点之前访问带有实例名称的静态方法,比如

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

有关替代方法的任何建议吗?

2 个答案:

答案 0 :(得分:2)

听起来你真正想要的是“类型类”或“见证”,这是一种尚不支持的语言功能,但this issue跟踪此功能的实现,非常活跃。
目前在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)

一方面,这使您能够以多态方式访问类型上的静态成员,但不应过度使用according to 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类型的静态成员, IMult上的实例成员存在,所以它不再是“静态多态”,而是它可能会实现你的目标。

答案 1 :(得分:0)

我和&#34; 1&#34;上面,不要挂在类型课上 - 它们不存在,在某些方面,它们仍然不理想。

对我来说,你错过了一个抽象,把它想象成某种工厂或域实体,捕获你的静态方法,并简单地传递它。

type MultDomain<'a when 'a :> IMult> =
    abstract member foo :  float -> float

type PointDomain =
    interface MultDomain<Point> with
        member o.foo x = x + 3.0

(约束&#34;&#39; a:&gt; IMult&#34;在您的上下文中不需要,但表明您可以使用您尚未创建的对象的类型接口)

所以答案是 &#34;是的,只要你将它们映射到某种类型的实例方法,你可以多态调用&#34; ...或者也许 &#34;不,但您可以将它们映射到某种类型的实例方法,您可以多态调用这些方法&#34;。

(我个人从来没有静态方法,甚至避免构造函数!)