首页 文章

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

提问于
浏览
1

在改进我的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在参数数量上有所不同而没有创建ad-hoc types 并且混淆了泛型签名,如:

type ClassUsingTheDataSource<'a, 'b, 'ds when 'ds :> DataSource<'a,'b>> (dataSource: 'ds) =

2 回答

  • 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();
        }
    }
    
  • 1

    据我所知, ClassUsingTheDataSource 的构造函数参数没有理由是 'ds 的确切类型;它足以成为抽象类型 DataSource<'a, 'b> . 因此你可以像这样写:

    type ClassUsingTheDataSource<'a, 'b> (dataSource: DataSource<'a, 'b>) = // ...
    

    如果这是您害怕的,您仍然可以在没有显式强制转换的情况下调用此构造函数:

    let f() =
        ClassUsingTheDataSource(NotAbstract())
    
    // val f : unit -> ClassUsingTheDataSource<'a, 'b>
    

相关问题