سؤال

كنت أقرأ طبيعة المهام, منشور لستيفن توب.

public static Task RunAsync(Action action)
{
    var tcs = new TaskCompletionSource<Object>();
    ThreadPool.QueueUserWorkItem(_ =>
    {
        try
        {
            action();
            tcs.SetResult(null);
        }
        catch(Exception exc) { tcs.SetException(exc); }
    });
    return tcs.Task;
}

وبما أننا لم يعد يهمني ما هو نوع من T هو ، لقد تخلفت عن استخدام Object.ثم ، عندما Action يتم تنفيذه بنجاح, SetResult لا تزال تستخدم لنقل Task في RanToCompletion الحالة النهائية;ومع ذلك ، نظرا لأن قيمة النتيجة الفعلية غير ذات صلة, null يستخدم. أخيرا, RunAsync المرتجعات Task بدلا من Task<Object>.وبطبيعة الحال ، فإن مثيل taskالنوع لا يزال Task<Object>, ، لكننا لا نحتاج إلى الإشارة إليها على هذا النحو ، ولا يحتاج مستهلك هذه الطريقة إلى الاهتمام بتفاصيل التنفيذ هذه.

لا أفهم بشكل خاص لماذا يجب أن تعود الطريقة Task بدلا من Task<object> (وهذا هو السبب في أنني أكدت الجملة الجريئة).وأنا أعلم أن يتم تعيين طريقة للعودة Task لكن tcs هو TaskCompletionSource<Object>, ، ليس TaskCompletionSource (وهذا خطأ ، على ما أعتقد).

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

المحلول

ليس هناك غير عام TaskCompletionSource وبالنظر إلى كل ما تريده هو مهمة بدون نتيجة ، فإن النتيجة لا تهم.المتصل لا يعرف ولا يهتم في هذه الحالة أن المهمة هي في الواقع Task<object>, ، المتصل فقط awaitق ذلك ، ويحصل على استثناء إذا كان هناك واحد.المتصل غير مدرك للنتيجة الفعلية.

يتم تسهيل هذا بالطبع من خلال حقيقة أن Task<T> يرث من Task


من الشائع أيضا العثور على ملف Task<bool> التي ترجع كاذبة ، أو Task<int> مع 0.

نصائح أخرى

لا يوجد غير عام TaskCompletionSource فئة لإنشاء مثيلات Task التي ليست حالات Task<T>.هذا يترك خيارين لمعلمة النوع العام لـ TaskCompletionSource<T> عندما لا تهتم (أو لا تقدم) قيمة الإرجاع:

  1. استخدم نوعا موجودا عشوائيا ، مثل object, ، كنوع الإرجاع.اضبط القيمة على null للإشارة إلى الانتهاء من المهمة.
  2. استخدم نوعا محددا غير عام ، واضبط القيمة على null للإشارة إلى الانتهاء من المهمة.

عندما أقوم بإنشاء ملف TaskCompletionSource<T> مثال لغرض توفير Task مع عدم وجود قيمة إرجاع ، أفضل استخدام نوع مخصص غير عام للتأكد من أن الكود المستهلك لن يخطئ في الإرجاع Task كمثال على Task<T> حيث النتيجة لها معنى.

أولا ، أنا تحديد الفئة التالية (يمكن أن يكون private sealed class إذا كان متداخلا داخل نوع آخر):

internal sealed class VoidResult
{
}

ثم ، بدلا من استخدام TaskCompletionSource<object> لمصدر الانتهاء ، وأنا استخدم TaskCompletionSource<VoidResult>.منذ VoidResult لا يمكن الوصول إلى النوع عن طريق الاتصال بالرمز ، ولن يتمكن المستخدم من إرسال Task الاعتراض على مثيل Task<VoidResult>.

لا أفهم بشكل خاص لماذا يجب أن تعود الطريقة Task بدلا من Task<object>

لأنه عندما تعود Task<Object> هذا يعني أنه عند اكتمال هذه الطريقة ، ستنتج بعض القيمة المفيدة للنوع Object.في هذه الحالة ، لا ننتج أي نتيجة ، ولهذا السبب اختار ستيفن العودة Task.

إذا كنا نتعامل مع Func<Object> ثم العودة Task<Object> سيكون من المناسب ، كما Func سوف تنتج بعض النتائج ، قد نختار لإعادته.

لماذا TaskCompletionSource<Object>, ، ليس TaskCompletionSource?

لأنه لا يوجد شيء من هذا القبيل.لا يوجد غير عام TaskCompletionSource.

إذا كنت عاد Task<object>, ، ثم var result = await RunAsync(...) سوف يعود دائما null, ، لأن هذا هو ما تقوم بتعيين النتيجة عليه.

العميل لا يهتم بهذا ، لذلك عليك فقط إرجاع Task.

من الناحية المثالية ، يمكنك استخدام TaskCompletionSource داخليا ، بدلا من TaskCompletionSource<object>, ، ومجرد استدعاء شيء من هذا القبيل SetCompleted() بدلا من SetResult(null).لكن هذا النوع غير موجود.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top