كيفية الحصول على استثناء من المهمة عندما تنشئ المهمة الأحداث
-
28-09-2019 - |
سؤال
لدي السيناريو التالي. أ Task
هذا يولد الأحداث وقد يلقي استثناء:
public event EventHandler<EventArgs> MyEvent;
new Task(() =>
{
while (condition)
{
// Generate standard .NET event.
MyEvent(this, new EventArgs());
// Maybe throw exception.
if (somethingIsWrong) throw new Exception();
}
});
كل شيء واضح ومباشر. أستمع إلى الأحداث باستخدام Observable.FromEvent
:
var events =
Observable.FromEvent<EventArgs>(h => myClass.MyEvent += h,
h => myClass.MyEvent -= h);
events.Subscribe(
ev => DoSomethingOnNext(ev),
ex => DoSomethingOnError(ex),
() => DoSomethingOnCompleted());
كل هذا يعمل بشكل جيد عندما لا يحدث استثناء. عندما يتم إلقاء استثناء من قبل المهمة ، أود أن أعرف ذلك في بلدي. الاستثناء الآن "مخفي" داخل المهمة.
هل يمكنني القيام بذلك فقط عن طريق إنشاء حدث آخر عندما يحدث الاستثناء ، ولفه داخل IObservable
والاشتراك في هذا جديد يمكن ملاحظته؟ أم أن هناك طريقة أبسط؟
المحلول
وماذا عن هذا:
class Program
{
public event EventHandler<EventArgs> MyEvent;
static void Main(string[] args)
{
var myClass = new Program();
var task = new Task(() =>
{
for(var i=0; i<5; i++) {
// Generate standard .NET event.
myClass.MyEvent(myClass, new EventArgs());
}
throw new Exception();
});
var obsTask = task.ToObservable();
var events = Observable.FromEvent<EventArgs>(h => myClass.MyEvent += h, h => myClass.MyEvent -= h);
events.TakeUntil(obsTask).Subscribe(
ev => DoSomethingOnNext(ev),
ex => DoSomethingOnError(ex),
() => DoSomethingOnCompleted());
task.Start();
Console.ReadKey();
}
private static void DoSomethingOnCompleted()
{
Console.WriteLine("DoSomethingOnCompleted");
}
private static void DoSomethingOnError(Exception ex)
{
Console.WriteLine("DoSomethingOnError:" + ex.ToString());
}
private static void DoSomethingOnNext(IEvent<EventArgs> ev)
{
Console.WriteLine("DoSomethingOnNext:" + ev.ToString());
}
الإخراج هو:
dosomethingonnext: system.collections.generic.event1[System.EventArgs]
DoSomethingOnNext:System.Collections.Generic.Event
1 [System.EventArgs] DosomethingOntext: System.Collections.generic.event1[System.EventArgs]
DoSomethingOnNext:System.Collections.Generic.Event
1 [System.EventArgs] dosomethingOnting: System.Collections.generic.event`1 [System.EventArgs] dosomethingOnerror: System.AggregateException: حدث واحد أو أكثر من الأخطاء. ---> System.Exception: تم طرح استثناء من النوع "System.Exception". في rxdisposetests.program. <> C_DisplayClass9.b_0 () في C: Users Richard.hein Documents Visual Studio 2010 Projects rxconsole rxdisposetests program.cs: السطر 25 في System.Threading.tasks.task.innerinvoke () في system.Threading.tasks. Task.execute () --- نهاية تتبع مكدس الاستثناء الداخلي --- ---> (استثناء داخلي #0) System.Exception: استثناء من النوع "System.Exception". في rxdisposetests.program. <> C_DisplayClass9.b_0 () في C: Users Richard.hein Documents Visual Studio 2010 Projects rxconsole rxdisposetests program.cs: الخط 25 في System.Threading.tasks.task.innerinvoke () في system.threading.tasks. Task.execute () <---
تعديل:
لست متأكدًا مما إذا كان Takeuntil حلًا جيدًا ، لأن المهمة قد تُرجع شيئًا آخر غير الاستثناءات ، أليس كذلك؟ لذلك هذا يمكن أن يعمل:
var events = Observable.CreateWithDisposable<IEvent<EventArgs>>(observer =>
{
var eventObs = Observable.FromEvent<EventArgs>(
h => myClass.MyEvent += h, h => myClass.MyEvent -= h);
task.ToObservable().Subscribe(_ => { }, observer.OnError, observer.OnCompleted);
return eventObs.Subscribe(observer.OnNext, observer.OnError, observer.OnCompleted);
});
events.Subscribe(
ev => DoSomethingOnNext(ev),
ex => DoSomethingOnError(ex),
() => DoSomethingOnCompleted());