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