القائم على الحدث المتزامن في#C;أي إعادة بيع ديون عامة ممكن ؟

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

سؤال

بعض واجهات برمجة التطبيقات ، مثل WebClient استخدام القائم على الحدث المتزامن نمط.في حين أن هذا يبدو بسيطا و ربما يعمل بشكل جيد في المتباعدة التطبيق (مثلا ، BackgroundWorker في واجهة المستخدم) ، فإنه لا سلسلة معا بشكل جيد للغاية.

على سبيل المثال, هنا البرنامج الذي مؤشرات حتى المتزامن العمل لا يمنع.(تخيل هذا يحدث في ملقم التطبيق ودعا مئات المرات-أنت لا تريد أن كتلة الخاص بك ThreadPool المواضيع.) نحصل على 3 المتغيرات المحلية ("الدولة") ، ثم جعل 2 المتزامن المكالمات مع نتيجة تغذية الأولى في الطلب الثاني (لذلك لا يمكن أن تذهب الموازية).الدولة يمكن أن يتحور جدا (من السهل إضافة).

باستخدام WebClient الأمور في نهاية المطاف مثل التالية (أو كنت في نهاية المطاف خلق مجموعة من الكائنات تتصرف مثل الإغلاق):

using System;
using System.Net;

class Program
{
    static void onEx(Exception ex) {
        Console.WriteLine(ex.ToString());
    }

    static void Main() {
        var url1 = new Uri(Console.ReadLine());
        var url2 = new Uri(Console.ReadLine());
        var someData = Console.ReadLine();

        var webThingy = new WebClient();
        DownloadDataCompletedEventHandler first = null;
        webThingy.DownloadDataCompleted += first = (o, res1) => {
            if (res1.Error != null) {
                onEx(res1.Error);
                return;
            }
            webThingy.DownloadDataCompleted -= first;
            webThingy.DownloadDataCompleted += (o2, res2) => {
                if (res2.Error != null) {
                    onEx(res2.Error);
                    return;
                }
                try {
                    Console.WriteLine(someData + res2.Result);
                } catch (Exception ex) { onEx(ex); }
            };
            try {
                webThingy.DownloadDataAsync(new Uri(url2.ToString() + "?data=" + res1.Result));
            } catch (Exception ex) { onEx(ex); }
        };
        try {
            webThingy.DownloadDataAsync(url1);
        } catch (Exception ex) { onEx(ex); }

        Console.WriteLine("Keeping process alive");
        Console.ReadLine();
    }

}

هل هناك طريقة عامة إلى ريفاكتور هذا الحدث القائم المتزامن النمط ؟ (أولا-هاء.لا يجب كتابة مفصلة أساليب الإرشاد لكل API هذا مثل هذا؟) BeginXXX و EndXXX تجعل من السهل, ولكن هذا الحدث الطريقة لا يبدو أن توفر أي طريقة.

هل كانت مفيدة؟

المحلول

قد ترغب في النظر في F#. F# يمكن أتمتة هذا الترميز مع "العمل" الميزة.'08 PDC عرض F# التعامل مع غير متزامن طلبات ويب باستخدام المكتبة القياسية سير العمل يسمى async, الذي يعالج BeginXXX/EndXXX نمط ، ولكن يمكنك كتابة سير العمل لهذا الحدث نمط من دون الكثير من الصعوبة ، أو إيجاد المعلبة واحد.F# يعمل بشكل جيد مع C#.

نصائح أخرى

في الماضي لقد نفذت هذه باستخدام طريقة مكرر:في كل مرة تريد آخر URL المطلوب ، يمكنك استخدام "العائد العودة" إلى تمرير التحكم إلى البرنامج الرئيسي.بمجرد طلب التشطيبات البرنامج الرئيسي يدعو إلى التكرار تنفيذ الجزء التالي من العمل.

كنت على نحو فعال باستخدام C# compiler لكتابة الدولة آلة ل أنت.ميزة هو أنه يمكنك كتابة طبيعية المظهر C# كود في طريقة مكرر لدفع كل شيء.

using System;
using System.Collections.Generic;
using System.Net;

class Program
{
    static void onEx(Exception ex) {
        Console.WriteLine(ex.ToString());
    }

    static IEnumerable<Uri> Downloader(Func<DownloadDataCompletedEventArgs> getLastResult) {
        Uri url1 = new Uri(Console.ReadLine());
        Uri url2 = new Uri(Console.ReadLine());
        string someData = Console.ReadLine();
        yield return url1;

        DownloadDataCompletedEventArgs res1 = getLastResult();
        yield return new Uri(url2.ToString() + "?data=" + res1.Result);

        DownloadDataCompletedEventArgs res2 = getLastResult();
        Console.WriteLine(someData + res2.Result);
    }

    static void StartNextRequest(WebClient webThingy, IEnumerator<Uri> enumerator) {
        if (enumerator.MoveNext()) {
            Uri uri = enumerator.Current;

            try {
                Console.WriteLine("Requesting {0}", uri);
                webThingy.DownloadDataAsync(uri);
            } catch (Exception ex) { onEx(ex); }
        }
        else
            Console.WriteLine("Finished");
    }

    static void Main() {
        DownloadDataCompletedEventArgs lastResult = null;
        Func<DownloadDataCompletedEventArgs> getLastResult = delegate { return lastResult; };
        IEnumerable<Uri> enumerable = Downloader(getLastResult);
        using (IEnumerator<Uri> enumerator = enumerable.GetEnumerator())
        {
            WebClient webThingy = new WebClient();
            webThingy.DownloadDataCompleted += delegate(object sender, DownloadDataCompletedEventArgs e) {
                if (e.Error == null) {
                    lastResult = e;
                    StartNextRequest(webThingy, enumerator);
                }
                else
                    onEx(e.Error);
            };

            StartNextRequest(webThingy, enumerator);
        }

        Console.WriteLine("Keeping process alive");
        Console.ReadLine();
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top