【问题标题】:Clear all event handlers in F#?清除 F# 中的所有事件处理程序?
【发布时间】:2019-11-18 10:53:45
【问题描述】:

如果我在 C# 时代没记错的话,有一种方法可以取消订阅事件中的所有事件处理程序,而无需为每个事件处理程序执行 -= 操作:将 null 分配给事件。

但是,似乎在 F# 中这是不可能的?我找到了方法TriggerPublishSubscribeAddRemove。拥有Clear 一个或类似的东西会很方便。也许很容易实现一个可以实现这一点的自定义事件?

【问题讨论】:

标签: f# c#-to-f#


【解决方案1】:

据我所知,标准 F# Event<'T> 类型无法做到这一点。即使您定义了一个事件并将其标记为CLIEvent,生成的代码也会使用addremove 方法定义一种自定义类型的事件,因此似乎没有办法删除所有处理程序。

但是,如果您需要定义自己的支持此功能的 F# 事件,您实际上可以自己实现它。您可以实现类似Event<'T> 的东西,它使用ResizeArray 跟踪事件处理程序,并在被要求执行此操作时删除所有处理程序。你需要做的就是实现IObservable(或者如果你想要更多的方法,IEvent接口)。

以下内容不能正确处理并发并且可能会中断,但它显示了这个想法:

open System

type RemovableEvent<'T> () = 
  let handlers = ResizeArray<Handler<_>>()
  member x.Trigger(v) = 
    for h in handlers do h.Invoke(x, v)
  member x.Clear() = 
    handlers.Clear()
  member x.Publish = 
    { new IEvent<'T> with
        member x.AddHandler(h) = handlers.Add(h)
        member x.RemoveHandler(h) = handlers.Remove(h) |> ignore
        member x.Subscribe(h) =
          let h = Handler<_>(fun _ v -> h.OnNext v)
          handlers.Add(h)
          { new IDisposable with
            member x.Dispose() = handlers.Remove(h) |> ignore } }

let re = RemovableEvent<_>()
re.Publish.Add(printfn "Hello %s")
re.Publish.Add(printfn "Hello again %s")
re.Trigger("world")
re.Clear()

【讨论】:

    【解决方案2】:

    这句话确实证实了托马斯的回答。

    来自 Riccardo Terrell 的 Concurrency in .NET,Manning Publications 出版,2018 年,第 6 章 “在使用 F# 构建反应式系统时,可以选择(和使用)Observable 或 Event;但为了避免内存泄漏,首选是 Observable。使用 F# Event 模块时,组合事件附加到原始事件,并且他们没有可能导致内存泄漏的取消订阅机制。相反,Observable 模块提供了订阅操作符来注册一个回调函数。该操作符返回一个 IDisposable 对象,该对象可用于停止事件流处理和 通过一次 Dispose 方法调用,取消注册管道中所有订阅的可观察(或事件)处理程序。"

    【讨论】:

      猜你喜欢
      • 2012-09-04
      • 2021-10-29
      • 1970-01-01
      • 1970-01-01
      • 2010-10-22
      • 1970-01-01
      相关资源
      最近更新 更多