在改进我的F#的过程中,我一直在尝试类型推断和generics
我很常常为abstract classes和interfaces中的抽象方法准备类型签名所需的工作感到困惑,因为(a)类型签名是乱七八糟的,(b)当我不知道时确切类型签名的样子(我通常从抽象类开始然后派生)。
这是(b)场景的玩具示例,我不知道派生类是否可能需要其他参数来完成其任务。我只知道我希望课程提供一个事件(feedAvailable
),并有两个返回单位的操作(Activate
和Deactivate
)。
[<AbstractClass>]
type DataSource () =
let mutable isActive = false
let feedAvailable = new Event<_> ()
abstract member Activate: _ -> unit
abstract member Deactivate: _ -> unit
type NotAbstract () =
inherit DataSource ()
override this.Activate (a: int) =
printfn "active: a = %i" a
override this.Deactivate (a: float) =
printfn "Stopped: a = %i" a
type NotAbstractTextual () =
inherit DataSource ()
override this.Activate (a: string, b: int) =
printfn "active: a = %i" a
override this.Deactivate (a: string, b: string) =
printfn "Stopped: a = %i" a
以下代码无法编译。 是否有一个技巧来推迟抽象类和接口中函数的类型签名?
一种解决方案可能是使用generics。
[<AbstractClass>]
type DataSource<'a, 'b> () =
let isActive = false
let feedAvailable = new Event<_> ()
abstract member Activate: 'a -> unit
abstract member Deactivate: 'b -> unit
type NotAbstract<'a, 'b> () =
inherit DataSource<'a, 'b> ()
override this.Activate (a) =
printfn "something"
override this.Deactivate (b) =
printfn "something"
type NotAbstractTextual<'a, 'b> () =
inherit DataSource<'a, 'b> ()
override this.Activate (a, b) =
printfn "something else"
override this.Deactivate (a,b,c) =
printfn "something else"
然而,这并没有解决所有问题,f.ex在参数数量方面有所不同而没有创建临时types
并且混淆了泛型签名,如下所示:
type ClassUsingTheDataSource<'a, 'b, 'ds when 'ds :> DataSource<'a,'b>> (dataSource: 'ds) =
答案 0 :(得分:1)
据我所知,ClassUsingTheDataSource
的构造函数参数没有理由是'ds
的确切类型;它是抽象类型DataSource<'a, 'b>
就足够了。因此你可以这样写:
type ClassUsingTheDataSource<'a, 'b> (dataSource: DataSource<'a, 'b>) = // ...
如果这是你害怕的话,你仍然可以在没有显式演员的情况下调用这个构造函数:
let f() =
ClassUsingTheDataSource(NotAbstract())
// val f : unit -> ClassUsingTheDataSource<'a, 'b>
答案 1 :(得分:0)
我很确定你想做什么是不可能的。
您尝试在DataSource上创建两个成员函数,但是要使子类型具体。当通用参数不是实际类型的一部分时,您不能这样做。这对F#来说不是问题,你也无法在C#中做到这一点,请参阅下文,了解你可以在C#中做些什么。
对不起,我不能给你更深入的解释。
public abstract class Foo
{
public abstract string Activate<T>(T t);
public abstract string Deactivate<T>(T t);
}
public class Bar : Foo
{
public override string Activate<T>(T t)
{
throw new NotImplementedException();
}
public override string Deactivate<T>(T t)
{
throw new NotImplementedException();
}
}