2017-09-23 13 views
1

클래스 생성자를 호출하는 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

답변

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 유형의 인스턴스가있는 경우에만 작동하므로이 솔루션도 작동하지 않을 수 있습니다.

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 

을 그리고 정의 할 수 있습니다

3) 그냥 그것을 필요로 다른 어떤 함수에 푸 기능을 전달합니다 Point, 방금 가지고있어

interface Types.IMult with 
    member this.Foo x = Point.foo x 

이것은 y 당신이 원하는 모든 것.그러면이 멤버는 Point 유형의 정적 멤버 인 인스턴스 멤버 인 IMult에 존재하므로 더 이상 실제로 "정적 다형성"이 아니지만 목표를 달성 할 수 있습니다.

+0

이것은 내 머리 위로 조금이지만, 나는 1과 3을 보았다. (나는 2를 보게 될 것이다. 두 경우 모두 코드에서 "점"이라는 단어를 사용했습니다. 그러나 런타임에 나는 어떤 클래스를 사용하고 있는지, 그것이 IMult로부터 상속받은 Point 또는 다른 클래스인지 알지 못합니다. 따라서이 두 가지 제안 (1과 3)은 문제를 해결하지 못하는 것 같습니다. 내가 놓친 게 있니? – Soldalma

+1

@ 솔달마, 그렇습니다. 다형성을 높이기를 원할 수도 있습니다. 'pt' 변수와 같은 레벨에서 다형 함수/인터페이스를 정의해야합니다. 예를 들어 옵션 1의 경우 'fooable : IFoo <'a> = fooablePoint'를'pt'와 동시에 사용하면 함께 갈 것입니다 (''bar ''와 함께 또는 대신''fooable''을 전달할 것입니다). 옵션 # 2의 경우'let foo : float -> float = Point.foo'를'pt'와 같은 위치에 정의 할 것이고,'pt'와 나란히 갈 것입니다. 타입 클래스가없는'pt'로 "묶어 버릴"방법이 없습니다. –

+1

@Soldalma,'IMult' 내부에서 여전히'abstract member foo : float -> float'을 정의 할 수 있고'Point' 내에'this.Foo x = Point.foo x 인 인터페이스 Types.IMult 만 있으면됩니다. ', 그것은 당신에게 당신이 원하는 모든 것을 줄 수 있습니다. 그러면 그 멤버는'Point' 타입의 정적 멤버와 IMult'의 인스턴스 멤버로 존재하지만 실제로는 "정적 다형성"이 아닙니다. –

0

위의 "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은"당신의 맥락에서 필요하지만 당신은 당신이이 인터페이스에서 만들 아직 객체의 유형에 사용할 수 있음을 보여줍니다되지 않음) 때문에

을 대답은 "네, 다형성으로"... 또는 어쩌면 "을 호출 할 수있는 일부 유형의 인스턴스 메소드에 맵핑하는 한, 폴리모픽으로 호출 할 수있는 일부 유형의 인스턴스 메소드에 맵핑 할 수 있습니다 ".

(개인적으로 나는 정적 메서드를하지 않아도, 심지어 생성자를 피하기!)