كيفية الحصول على استثناء من المهمة عندما تنشئ المهمة الأحداث

StackOverflow https://stackoverflow.com/questions/4275307

  •  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.Event1 [System.EventArgs] DosomethingOntext: System.Collections.generic.event1[System.EventArgs] DoSomethingOnNext:System.Collections.Generic.Event1 [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());
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top