gpt4 book ai didi

events - 如何弱订阅事件/可观察量

转载 作者:行者123 更新时间:2023-12-02 09:25:51 25 4
gpt4 key购买 nike

我有一个类似静态的(发布者生命周期 = 应用程序生命周期)事件,我需要从 View 中订阅。我无法可靠地确定 View 何时导航离开(Xamarin.Forms NavigationPage 中按下导航栏后退按钮就是一个示例),因此我无法确定 View 何时应取消订阅可观察对象。 (我知道可以在 OnAppearing/OnDisappearing 中订阅/取消订阅,但这会带来一系列问题,我不会在这里详细介绍。)

因此,我发现自己需要让 View 弱订阅该事件,即允许 View 被垃圾收集而不必取消订阅该事件。理想情况下,我想要一些可以按照 myObj.myEvent |> Observable.AsWeak |> Observable.Subscribe ...myObj.myEvent |> Observable.SubscribeWeakly 的方式使用的东西...,或简单地 myObj.myEvent.SubscribeWeakly ...

不幸的是我不知道如何实现这个。我听说过System.WeakReference类,但这对我来说都是非常新的,我不知道如何正确使用它 - 我见过的大多数例子对于我想要做的事情来说似乎过于复杂,这意味着要么我想要不同的东西,要么有表面之下的陷阱比我想象的要多得多。

如何在 F# 中订阅事件/可观察对象,同时允许订阅者在不取消订阅的情况下进行垃圾收集?

类似但不重复的问题:

最佳答案

我已经得到了一个相对简单的函数,似乎可以正常工作,尽管我真的不知道我在做什么,所以我把它放在Code Review SE 。它基于 Samuel Jack 的 Weak Events in .Net, the easy way 中的信息。以及 CodeProject 的 Weak Events in C# 中的解决方案 4 .

实现

module Observable =
open System

// ('a -> 'b -> unit) -> 'a -> IObservable<'b>
let subscribeWeakly callback target source =

let mutable sub:IDisposable = null
let mutable disposed = false
let wr = new WeakReference<_>(target)

let dispose() =
lock (sub) (fun () ->
if not disposed then sub.Dispose(); disposed <- true)

let callback' x =
let isAlive, target = wr.TryGetTarget()
if isAlive then callback target x else dispose()

sub <- Observable.subscribe callback' source
sub

使用示例

请参阅下面的 WeakSubscriber 类型。

重要

您必须使用回调的 me 参数来调用相关方法。如果您在回调中使用this,由于上述文章中描述的原因,您仍然会得到一个强引用。出于同样的原因(我猜?),您无法在使用 let 定义的类中调用“普通”函数。 (但是,您可以将该方法定义为 private。)

测试

帮助类:

type Publisher() =
let myEvent = new Event<_>()
[<CLIEvent>] member this.MyEvent = myEvent.Publish
member this.Trigger(x) = myEvent.Trigger(x)


type StrongSubscriber() =

member this.MyMethod x =
printfn "Strong: method received %A" x

member this.Subscribe(publisher:Publisher) =
publisher.MyEvent |> Observable.subscribe this.MyMethod
publisher.MyEvent |> Observable.subscribe
(fun x -> printfn "Strong: lambda received %A" x)


type WeakSubscriber() =

member this.MyMethod x =
printfn "Weak: method received %A" x

member this.Subscribe(publisher:Publisher) =
publisher.MyEvent |> Observable.subscribeWeakly
(fun (me:WeakSubscriber) x -> me.MyMethod x) this
publisher.MyEvent |> Observable.subscribeWeakly
(fun _ x -> printfn "Weak: lambda received %A" x) this

实际测试:

[<EntryPoint>]
let main argv =

let pub = Publisher()

let doGc() =
System.GC.Collect()
System.GC.WaitForPendingFinalizers()
System.GC.Collect()
printfn "\nGC completed\n"

let someScope() =
let strong = StrongSubscriber()
let weak = WeakSubscriber()
strong.Subscribe(pub)
weak.Subscribe(pub)

doGc() // should not remove weak subscription since it's still in scope
printfn "All subscribers should still be triggered:"
pub.Trigger(1)

someScope()

doGc() // should remove weak subscriptions
printfn "Weak subscribers should not be triggered:"
pub.Trigger(2)

System.Console.ReadKey() |> ignore

0

输出:

GC completed

All subscribers should still be triggered:
Strong: method received 1
Strong: lambda received 1
Weak: method received 1
Weak: lambda received 1

GC completed

Weak subscribers should not be triggered:
Strong: method received 2
Strong: lambda received 2

关于events - 如何弱订阅事件/可观察量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45899576/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com