Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 如何检查F中是否正在处理事件#_F# - Fatal编程技术网

F# 如何检查F中是否正在处理事件#

F# 如何检查F中是否正在处理事件#,f#,F#,以下C代码的F等价物是什么?具体来说,我需要检查是否正在处理事件 protected virtual void OnClicked(ClickEventArgs e) { if (this.Clicked != null) //how can I perform this check in F# this.Clicked(this, e); } 本文说您不需要检查F#中的null事件,尽管我不知道他的引用是什么 唐·赛姆斯(Don Symes)的这篇文章非常详细地介绍了

以下C代码的F等价物是什么?具体来说,我需要检查是否正在处理事件

protected virtual void OnClicked(ClickEventArgs e) {
    if (this.Clicked != null) //how can I perform this check in F#
        this.Clicked(this, e);
}
本文说您不需要检查F#中的null事件,尽管我不知道他的引用是什么

唐·赛姆斯(Don Symes)的这篇文章非常详细地介绍了F#事件。看起来事件不属于F中的类#

综上所述,

是的,现在的活动是一流的 F#langauge中的值。的确 事件并不是一个单独的概念 所有这些都是语言设计, 事件只是类型的值 Microsoft.FSharp.Idioms.IEvent和 .NET事件实际上是公正的 此类型的属性

C#的限制之一是 事件只能作为成员存在 在课堂上。对于F#模型, 只需创建新的事件值即可 作为值作为任何表达式的一部分


通常,您不需要在F#(事件基础结构为您检查)中执行该检查:

类型T()=
设ev=新事件()
[]
成员x.Event=ev.Publish
成员x.OnClicked()=
ev.Trigger()

好吧,我想我把这件事弄明白了。以“IEvent模块的实现”一节为线索

而不是以下内容:

let validationFailedEvent = new Event<DataValidationEventHandler, DataValidationEventArgs>()

实现
requireSubscriptionEvent
的另一种方法是在现有的
事件
功能的基础上构建(使用组合),只需添加一个计数器来计算已注册处理程序的数量,并添加一个属性
HasListeners
(如果需要,甚至可以发布侦听器的数量…)

这使得代码更容易使用,也更安全,因为如果不检查它是否有列表,它仍将像通常的F#代码一样工作。如果你想进行检查,你可以

type RequiresSubscriptionEvent<_>() = 
  let evt = new Event<_>()
  let mutable counter = 0
  let published = 
    { new IEvent<_> with
      member x.AddHandler(h) = 
        evt.Publish.AddHandler(h)
        counter <- counter + 1; 
      member x.RemoveHandler(h) = 
        evt.Publish.RemoveHandler(h)
        counter <- counter - 1; 
      member x.Subscribe(s) = 
        let h = new Handler<_>(fun _ -> s.OnNext)
        x.AddHandler(h)
        { new System.IDisposable with 
            member y.Dispose() = x.RemoveHandler(h) } }
  member x.Trigger(v) = evt.Trigger(v)
  member x.Publish = published
  member x.HasListeners = counter > 0
类型requireSubscriptionEvent()=
让evt=新事件()
设可变计数器=0
让发布=
{新事件与
成员x.AddHandler(h)=
evt.Publish.AddHandler(h)
计数器0
示例用法:

type Demo() =
  let evt = new RequiresSubscriptionEvent<_>()
  [<CLIEvent>]
  member x.OnSomething = evt.Publish
  member x.FooThatFiresSomething() = 
    if evt.HasListeners then
      evt.Trigger("foo!")
    else
      printfn "No handlers!"
类型Demo()=
设evt=new RequiresSubscriptionEvent()
[]
成员x.OnSomething=evt.Publish
成员x.FoothatfiresMething()=
如果evt.HasListeners那么
触发器(“foo!”)
其他的
printfn“没有处理程序!”

尽管这不是标准F#库的一部分,但它显示了F#头等事件的巨大优势。如果缺少一些功能,您可以自己实现它!

我遵循kvb的建议,将此逻辑放在一个类中。我从F#源复制了事件,并添加了一个处理属性,用于检查Delegat是否我尝试添加到,然后从事件中删除处理程序,以确保它被设置回null,事实上确实如此

    type EventEx<'Delegate,'Args when 'Delegate : delegate<'Args,unit> and 'Delegate :> System.Delegate >() = 
        let mutable multicast : System.Delegate = null
        static let argTypes = 
            let instanceBindingFlags = BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic ||| BindingFlags.DeclaredOnly
            let mi = typeof<'Delegate>.GetMethod("Invoke",instanceBindingFlags)
            mi.GetParameters() |> (fun arr -> arr.[1..]) |> Array.map (fun p -> p.ParameterType)

        member x.Handled = (multicast <> null)

        member x.Trigger(sender:obj,args:'Args) = 
            match multicast with 
            | null -> ()
            | d -> 
                if argTypes.Length = 1 then 
                    d.DynamicInvoke([| sender; box args |]) |> ignore
                else
                    d.DynamicInvoke(Array.append [| sender |] (Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(box args))) |> ignore
        member x.Publish = 
            { new IEvent<'Delegate,'Args> with 
                member x.AddHandler(d) =
                    multicast <- System.Delegate.Combine(multicast, d)
                member x.RemoveHandler(d) = 
                    multicast <- System.Delegate.Remove(multicast, d) 
                member e.Subscribe(observer) = 
                   let h = new Handler<_>(fun sender args -> observer.OnNext(args))
                   (e :?> IEvent<_,_>).AddHandler(h)
                   { new System.IDisposable with 
                        member x.Dispose() = (e :?> IEvent<_,_>).RemoveHandler(h) } }
键入EventEx和'Delegate:>System.Delegate>()=
让可变多播:System.Delegate=null
静态let argTypes=
让instanceBindingFlags=BindingFlags.Instance | | | | BindingFlags.Public | | | | BindingFlags.declareOnly
设mi=typeof()
|d->
如果argTypes.Length=1,则
d、 DynamicInvoke([|发送方;框参数])|>忽略
其他的
d、 DynamicInvoke(Array.append[| sender |](Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(框参数))|>忽略
成员x.发布=
{新事件与
成员x.AddHandler(d)=
多播IEvent).AddHandler(h)
{new System.IDisposable with
成员x.Dispose()=(e:?>IEEvent.RemoveHandler(h)}

如果没有处理事件,我想抛出一个异常(类似于未设置XmlReaderSettings.ValidationEventHandler时XmlReader抛出异常的方式)。此代码将从C#调用。没错,您不需要检查是否附加了处理程序来触发事件。我需要检查其他原因。(见我在kvb帖子中的评论)呵呵……我在谷歌搜索“F夏普听众”它得出了关于音符F#和听众的结果。因此,如果我们弄明白了这一点,我们可以让音乐家知道如何检查是否有人在听。没有F#专家,但我读了这篇文章,看起来他在重复一组观察者。也许这可以给你一些想法。也可以让你清楚地看到e C#编译器确实会把很多事情都抹掉。关于C#的性感,你当然可以把这个逻辑封装在你自己的
requireSubscriptionEvent+1中。我同意你关于空检查的看法,但是空检查只是如何找出一个事件是否在C#中处理。在F#中可以做得不同。也许是监听器s可以存储在一个列表(可以检查是否为空)或一个选项(检查是否为空)中。不确定发布F#功能请求的最佳位置,但我在hubbs.net上发布了一个请求,以在事件中公开多播代理成员(和相关类型)。这将使此检查更容易。下面是功能请求:不幸的是,如果需要的话,我不认为这将正确处理同一物理委托的重复添加/删除。我也不认为这将保持侦听器的准确计数,因为您不知道对添加/删除处理程序的调用是否更改了invocat离子列表。嗯,你是对的。我希望AddHandler/RemoveHandler在这些奇怪的情况下会抛出一个异常。如果你多次添加一个处理程序,效果会很好,但不幸的是,你永远不知道删除处理程序是否有作用(你可以删除未添加的处理程序,它不会抱怨)。。。
type RequiresSubscriptionEvent<_>() = 
  let evt = new Event<_>()
  let mutable counter = 0
  let published = 
    { new IEvent<_> with
      member x.AddHandler(h) = 
        evt.Publish.AddHandler(h)
        counter <- counter + 1; 
      member x.RemoveHandler(h) = 
        evt.Publish.RemoveHandler(h)
        counter <- counter - 1; 
      member x.Subscribe(s) = 
        let h = new Handler<_>(fun _ -> s.OnNext)
        x.AddHandler(h)
        { new System.IDisposable with 
            member y.Dispose() = x.RemoveHandler(h) } }
  member x.Trigger(v) = evt.Trigger(v)
  member x.Publish = published
  member x.HasListeners = counter > 0
type Demo() =
  let evt = new RequiresSubscriptionEvent<_>()
  [<CLIEvent>]
  member x.OnSomething = evt.Publish
  member x.FooThatFiresSomething() = 
    if evt.HasListeners then
      evt.Trigger("foo!")
    else
      printfn "No handlers!"
    type EventEx<'Delegate,'Args when 'Delegate : delegate<'Args,unit> and 'Delegate :> System.Delegate >() = 
        let mutable multicast : System.Delegate = null
        static let argTypes = 
            let instanceBindingFlags = BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic ||| BindingFlags.DeclaredOnly
            let mi = typeof<'Delegate>.GetMethod("Invoke",instanceBindingFlags)
            mi.GetParameters() |> (fun arr -> arr.[1..]) |> Array.map (fun p -> p.ParameterType)

        member x.Handled = (multicast <> null)

        member x.Trigger(sender:obj,args:'Args) = 
            match multicast with 
            | null -> ()
            | d -> 
                if argTypes.Length = 1 then 
                    d.DynamicInvoke([| sender; box args |]) |> ignore
                else
                    d.DynamicInvoke(Array.append [| sender |] (Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(box args))) |> ignore
        member x.Publish = 
            { new IEvent<'Delegate,'Args> with 
                member x.AddHandler(d) =
                    multicast <- System.Delegate.Combine(multicast, d)
                member x.RemoveHandler(d) = 
                    multicast <- System.Delegate.Remove(multicast, d) 
                member e.Subscribe(observer) = 
                   let h = new Handler<_>(fun sender args -> observer.OnNext(args))
                   (e :?> IEvent<_,_>).AddHandler(h)
                   { new System.IDisposable with 
                        member x.Dispose() = (e :?> IEvent<_,_>).RemoveHandler(h) } }