Здравствуйте, cadet354, Вы писали:
C>Доброго времени,
C>есть Event, на него подписываются делегаты, как вызвать их асинхронно.
C>Сейчас при trigger они вызываются последовательно, к тому же если один handler упадет с exception другие не будут вызваны вообще.
C>Может помочь в этом Rx ?
стандартный Event<_, _> такого точно не сумеет, насчет Rx не уверен, но тоже есть сомнения. IMO проще сделать свой вариант Event, навроде такого (функционал для поддержки работы из нескольких потоков добавлять самому по вкусу)
type Invoker<'D, 'A> = delegate of 'D * obj * 'A -> unit
type Event<'D, 'A when 'D :> Delegate and 'D : delegate<'A, unit> and 'D : null>() =
static let invoker = Delegate.CreateDelegate(typeof<Invoker<'D, 'A>>, typeof<'D>.GetMethod("Invoke")) :?> Invoker<'D, 'A>
let mutable multicast : 'D = null
member x.Trigger(sender:obj,args: 'A) =
match multicast with
| null -> ()
| d -> invoker.Invoke(d, sender, args) // DelegateEvent uses: d.DynamicInvoke(args) |> ignore
member x.TriggerAsync(sender : obj, args : 'A) =
let delegates =
match multicast with
| null -> Array.empty
| d -> d.GetInvocationList()
delegates
|> Seq.map (fun d -> async { invoker.Invoke(d :?> _, sender, args) } )
|> Async.Parallel
|> Async.Ignore
member x.Publish =
{ new IDelegateEvent<'D> with
member x.AddHandler(d) =
multicast <- System.Delegate.Combine(multicast, d) :?> 'D
member x.RemoveHandler(d) =
multicast <- System.Delegate.Remove(multicast, d) :?> 'D }
такая реализация будет как минимум быстрее стандартной, которая внутри для вызова делегата использует Delegate.DynamicInvoke