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

问题描述:

我需要调用类的一个静态成员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 

有什么建议?

+0

您可以将其定义为一个扩展方法,但为什么你需要用实例来调用它呢?它似乎不受实例本身的影响。 – Gustavo

+1

查看静态解析的类型约束。 –

+0

@Gustavo - 我不需要用实例调用它。事实上它不依赖于实例(因为它是静态的)。我想用实例调用它,因为我不能用类名称来调用它,因为在调用的时候,类可以是几种选择中的任何一种。如果F#让我从实例中调用它,则问题将得到解决。 – Soldalma

这听起来像你真正需要的是“类型班”或“目击者”,这是一种语言功能,目前还不支持,但追踪此功能实施的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 

这可能会给y ou你想要的一切。那么该成员将作为Point类型的一个静态成员存在,IMult上的一个实例成员,因此它不再是真正的“静态多态”,但它可能实现您的目标。

+0

这有点凌驾于我的头上,但我已经看过1和3(我会看2,后面看起来更复杂)。在这两种情况下,你都在代码中使用了“Point”这个词。但是在运行时我不知道我使用的是什么类,它可能是Point或从IMult继承的另一个类。所以这两个建议(1和3)似乎不能解决问题。我错过了什么吗? – Soldalma

+1

@Soldalma,是的,你可能希望它多态性更高。您需要将多态函数/接口定义在与您的'pt'变量相同的级别上。因此,对于选项#1,您可以定义,例如'let fooable:IFoo = fooablePoint'与'pt'同时,他们会一起走过(你可以将'fooable'与'pt'一起或代替'pt'传递给'bar')。对于选项#2,您可以在与'pt'相同的位置定义'let foo:float - > float = Point.foo',它也会与'pt'一起使用。没有类型类的'pt'没有办法“捆绑它”。 –

+1

@Soldalma,请记住,您仍然可以在'IMult'内部定义'abstract member foo:float - > float',并且在'Point'内部,使用'interface Types.IMult'成员this.Foo x = Point.foo x ',这可能会给你想要的一切。然后该成员将存在_both_作为'Point'类型的静态成员,以及'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”是不是在你的情况下必需的,但表明你可以使用你还没有在此界面中创建对象的类型)

所以答案是 “是的,只要您将它们映射到可以多态调用的某种类型的实例方法”...或者也许 “否,但您可以将它们映射到某种类型的实例方法,您可以以多态方式调用”。

(我个人从来没有静态方法,甚至避免建设者!)