2011-08-11 17 views
6

मेरे पास एक छोटा एसिंक कार्य है जिसे इसे शुरू करने के बाद अक्सर रद्द करने की आवश्यकता होगी। "टास्क" श्रेणी में एक IsCanceled संकेतक है जो मुझे लगता है कि यह सुनिश्चित करने के लिए सुविधाजनक होगा कि एसिंक कार्य पूरा होने के बिना रद्द कर दिया गया था, लेकिन जहां तक ​​मैं एक async कार्य को रद्द करने के रूप में चिह्नित करने का एकमात्र तरीका बता सकता हूं async फ़ंक्शन में एक कार्य CanceledException फेंकने के लिए। नियमित रूप से एक अपवाद फेंकना, ऐसी परिस्थिति को इंगित करने के लिए जो अप्रत्याशित रूप से होता है, मैं समझता हूं कि अपवादों का उपयोग कैसे किया जाना चाहिए। क्या किसी को एसिंक कार्य को रद्द करने के लिए एक बेहतर तरीका पता है जब इसे अक्सर होने की उम्मीद है?सी # async सीटीपी - मैं कार्य को रद्द करने के बिना रद्द किए गए एसिंक कार्य को कैसे चिह्नित करूं?

class MightBeCanceled<T> 
{ 
    public readonly T Value; 
    public readonly bool IsCanceled; 

    public MightBeCanceled(T value) { Value = value; IsCanceled = false; } 
    public static MightBeCanceled<T> Canceled = new MightBeCanceled<T>(default(T), true); 
    private MightBeCanceled(T value, bool isCanceled) { Value = value; IsCanceled = isCanceled; } 
} 

... 

static async Task<MightBeCanceled<int>> Foo() 
{ 
    if (someCancellationCondition) 
     return MightBeCanceled<int>.Canceled; 
    else 
     return new MightBeCanceled<int>(42); 
} 

static async void Bar() 
{ 
    var mightBeCanceled = await Foo(); 

    if (mightBeCanceled.IsCanceled) 
     ; // Take canceled action 
    else 
     ; // Take normal action 
} 

लेकिन यह लगता है (मैं संक्षिप्तता यहाँ के लिए कुछ अच्छे कोडिंग और शैली प्रथाओं पर ध्यान नहीं दिया गया है):

मेरे अगली सबसे अच्छा विकल्प एक संरचना है कि यह खुद IsCanceled संपत्ति है है वापस जाने के लिए है अनावश्यक और उपयोग करने में कठोर। उल्लेख नहीं है कि यह स्थिरता की समस्याओं का परिचय देता है क्योंकि दो IsCanceled (टास्क में से एक और MightBeCanceled में से एक) होगा।

+1

फू को कौन रद्द कर रहा है? इसे रद्द करने के लिए केवल कॉलर द्वारा रद्दीकरण किया जाना चाहिए –

उत्तर

2

समस्या यह है कि जब तक आप इसका इंतजार नहीं करना चुनते हैं तो अपवाद अनवरोधित होगा। तो await पर कॉल करने का कार्य का अर्थ है कि अंततः आप किसी बिंदु पर अपवाद का निरीक्षण करेंगे जब अंतिम मूल्य वापस किया जाएगा या यदि आप कार्य को पूरा करने की प्रतीक्षा करते हैं। हालांकि, अगर आप कभी परवाह नहीं करते हैं (यह आग है और भूल जाता है), तो अपवाद एक गैर मुद्दा है (अधिकांश भाग के लिए)।

मैं भी, यह थोड़ा अजीब लगता है, हमेशा अपवादों को संभालने के लिए कार्य को आजमाने/पकड़ने के लिए। हालांकि, इसके बारे में थोड़ा सा सोचें:

try 
{ 
    var myResult = await Foo(); 

    // Do Success Actions Here... 
} 
catch(AggregateException e) 
{ 
    e.Flatten().Handle(ex => 
     { 
      if(ex is OperationCanceledException) 
      { 
       // Do Canceled Thing Here 
       return true; 
      } 

      return false; 
     }); 
} 

यह बहुत दूर नहीं है। कई मायनों में, मैं एक और कार्य रद्द करने के बारे में सोचता हूं और मैं इसे कैसे करूँगा? ThreadAbortException? यह रद्दीकरण पर एक विशिष्ट अपवाद फेंकने के लिए अब तक प्रतीत नहीं होता है।

यह रद्दीकरण को संभालने के तरीके के लिए कई जगहों पर वकालत की गई है जो मैंने देखा है।

2

आमतौर पर रद्दीकरण का उद्देश्य एसिंक्रोनस एक्शन के आवेदक के लिए है कि यह कार्रवाई को बताने के लिए कि उसे प्रसंस्करण करना बंद कर देना चाहिए। इसके लिए आप एसिंक्रोनस विधि में CancellationToken पास करते हैं। यही कारण है कि एक कार्य का इंतजार है जो IsCancelled सेट खुद को फेंकता है। यह एक बाहरी उत्तेजित कार्रवाई के लिए एक असाधारण संकेत है। टास्क रद्दीकरण का उपयोग नियंत्रण प्रवाह के लिए नहीं किया जाना चाहिए, लेकिन केवल एसिंक एक्शन देने के विकल्प को जल्दी खत्म करने का विकल्प देना चाहिए, जो प्रतीक्षा करने वाले पार्टी ने संकेत दिया है कि अब यह परिणाम नहीं चाहता है।

यदि आप आंतरिक रूप से एसिंक्रोनस क्रियाएं रद्द कर दी जाती हैं, तो आप पहले ही अवधारणा को अधिभारित कर चुके हैं और मैं कहूंगा कि रद्दीकरण में उस अंतर को दर्शाते हुए यह सार्थक है और परिणाम कंटेनर पर आपके द्वारा प्रस्तावित तरीके के समान होना चाहिए। लेकिन रद्दीकरण अवधारणाओं के अंतर को दर्शाने के लिए MightBeCancelled<T> पर कॉल करने की बजाय, शायद InternallyCancellableResult<T> जैसे कुछ।