带抽象类的通配符类型推断

时间:2014-02-27 13:07:56

标签: interface f# abstract-class type-inference

在改进我的F#的过程中,我一直在尝试类型推断和generics

我很常常为abstract classesinterfaces中的抽象方法准备类型签名所需的工作感到困惑,因为(a)类型签名是乱七八糟的,(b)当我不知道时确切类型签名的样子(我通常从抽象类开始然后派生)。

这是(b)场景的玩具示例,我不知道派生类是否可能需要其他参数来完成其任务。我只知道我希望课程提供一个事件(feedAvailable),并有两个返回单位的操作(ActivateDeactivate)。

[<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) = 

2 个答案:

答案 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();
    }
}