在 F# 中处理模式

Rob*_*don 6 f# dispose

在 F# 中,继承不像在 C# 中那么常见,但这并不意味着它从未被使用过。

如果我从 C# 中实现的类型继承IDisposable,我通常会使用Dispose 模式来抑制终结器。但是,我无法直接在 F# 中执行此操作,因为没有protected访问修饰符。

我在网上搜索了 F# 中 Dispose 模式的实现,但我只找到了对Dispose(). 是否有一种模式可以让我释放派生类中的非托管资源,同时仍然抑制终结器以优化性能?

为了使这个问题稍微不那么抽象,这是一个我想继承的典型抽象基类型:

[<AbstractClass>]
type ContentPage<'TViewModel, 'TView when 'TViewModel :> ReactiveViewModel and 'TViewModel : not struct>(theme: Theme) as this =
    inherit ContentPage()
    let messageReceived (message: AlertMessage) = this.DisplayAlert(message.Title, message.Message, message.Accept) |> ignore
    let mutable viewModel, listener = Unchecked.defaultof<'TViewModel>, Observable.Never<AlertMessage>().Subscribe(messageReceived)
    do base.BackgroundColor <- theme.Styles.BackgroundColor
    member __.ViewModel with get() = viewModel and set(value: 'TViewModel) = listener.Dispose(); viewModel <- value; listener <- value.MessageSent.Subscribe(messageReceived)
    abstract member CreateContent: unit -> View
    interface IViewFor<'TViewModel> with member __.ViewModel with get() = this.ViewModel and set(value) = this.ViewModel <- value
    interface IViewFor with member __.ViewModel with get() = (this :> IViewFor<'TViewModel>).ViewModel :> obj and set(value: obj) = (this :> IViewFor<'TViewModel>).ViewModel <- (value :?> 'TViewModel)
    interface IDisposable with member __.Dispose() = listener.Dispose()
    override __.OnAppearing() =
        base.OnAppearing()
        match box this.Content with
        | null -> this.Content <- this.CreateContent()
        | _ -> this |> ignore
Run Code Online (Sandbox Code Playgroud)

Dispose()如果我要实现 C# Dispose 模式的 F# 模拟,会是什么样子?

gra*_*bot 4

您无法Dispose直接在 f# 中实现调用链。base.Dispose()不会工作,因为baseis 类型ContentPage并且不会被隐式转换为IDisposable. base只允许成员访问,因此您也无法显式转换它。以下内容将无法编译。

type BrokenPage() =
    inherit ContentPage()

    interface IDisposable with 
        member __.Dispose() =
            (base :> IDisposable).Dispose()
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,需要另一种方法。由于 F# 中没有protected,因此该习惯用法仍然不完美。

type ContentPage() =
    abstract Close : unit -> unit

    default this.Close() = 
        // cleanup ContentPage here
        GC.SuppressFinalize(this)

    interface IDisposable with
        member this.Dispose() = 
            this.Close()


type SomePage() =
    inherit ContentPage()

    override this.Close() = 
        // cleanup SomePage here
        base.Close()

    interface IDisposable with
        member this.Dispose() = 
            this.Close()
Run Code Online (Sandbox Code Playgroud)