2013-03-18 6 views
13

निरंतर श्रृंखलाओं में अपवादों का प्रचार करने का उचित तरीका क्या है?निरंतर श्रृंखलाओं में अपवादों को प्रसारित करने का उचित तरीका क्या है?

t.ContinueWith(t2 => 
{ 
    if(t2.Exception != null) 
     throw t2.Exception; 

    /* Other async code. */ 
}) 
.ContinueWith(/*...*/); 

t.ContinueWith(t2 => 
{ 
    if(t2.IsFaulted) 
     throw t2.Exception; 

    /* Other async code. */ 
}) 
.ContinueWith(/*...*/); 

t.ContinueWith(t2 => 
{ 
    if(t2.Exception != null) 
     return t2; 

    /* Other async code. */ 
}) 
.ContinueWith(/*...*/); 

t.ContinueWith(t2 => 
{ 
    if(t2.IsFaulted) 
     return t2; 

    /* Other async code. */ 
}) 
.ContinueWith(/*...*/); 


t.ContinueWith(t2 => 
{ 
    t2.Wait(); 

    /* Other async code. */ 
}) 
.ContinueWith(/*...*/); 

t.ContinueWith(t2 => 
{  
    /* Other async code. */ 
}, TaskContinuationOptions.NotOnFaulted) // Don't think this one works as expected 
.ContinueWith(/*...*/); 
+0

मुझे लगता है कि यह सोचते कर रहा हूँ बजाय 't.ContinueWith की (टी = > ...) 'आप वास्तव में मतलब है टी। कंटिन्यूथ (टी 2 => ...)', है ना? – Geoff

+0

@ गीफ: हाँ, यह सही है। – ronag

उत्तर

1

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

task.ContinueWith(t => 
{ 
    //do stuff 
}, TaskContinuationOptions.OnlyOnRanToCompletion); 

आप स्पष्ट रूप से एक अपवाद के मामले को संभालने के लिए चाहते हैं (शायद प्रवेश करने के लिए, अपवाद अपवाद के कुछ अन्य प्रकार के होने के लिए फेंक दिया बदल (संभवतः अतिरिक्त जानकारी के साथ, या अस्पष्ट जानकारी के लिए नहीं होना चाहिए कि उजागर)) तो आप OnlyOnFaulted विकल्प (संभवतः एक सामान्य मामले निरंतरता के अतिरिक्त) के साथ एक निरंतरता जोड़ सकते हैं।

+1

इस दृष्टिकोण के साथ मैंने जो समस्या देखी है वह यह है कि यदि मैं परिणामस्वरूप कार्य वापस करता हूं और फिर श्रृंखला में चीजों को जोड़ना जारी रखता हूं, तो इस बिंदु से कोई अपवाद प्रचारित नहीं होगा ... – ronag

+0

यानी कोई अतिरिक्त जारी रखने वाला कोई भी जारी नहीं होगा अपवाद प्रसारित नहीं करेगा ... जो कोई अच्छा नहीं है। – ronag

0

OnlyOnFaulted विकल्प उन मामलों के लिए है जहां पिछले Task अपने कार्य को सही तरीके से निष्पादित नहीं कर सका। एक तरीका हर निरंतर कार्य में अपवाद को फिर से उखाड़ फेंक देगा, लेकिन यह खराब डिजाइन होगा।

यदि आप अपवाद को सामान्य वस्तु की तरह पास करना चाहते हैं तो इसे एक के रूप में देखें। Task अपवाद वापस करें और निरंतरता में Task.Result संपत्ति का उपयोग करें।

4

TaskContinuationOptions.OnlyOn... समस्याग्रस्त हो सकता है क्योंकि वे को जारी रखने का कारण बनते हैं यदि उनकी स्थिति पूरी नहीं हुई है। मुझे समझने से पहले मैंने लिखा कोड के साथ कुछ सूक्ष्म समस्याएं थीं।

इस तरह की जंजीर निरंतरता वास्तव में सही होने के लिए काफी कठिन है। अब तक का सबसे आसान नया है .NET 4.5 await कार्यक्षमता का उपयोग करना है। यह आपको इस तथ्य को अनदेखा करने की अनुमति देता है कि आप एसिंक्रोनस कोड लिख रहे हैं। आप सिंक्रोनस समतुल्य में जितनी जल्दी हो सके कोशिश/पकड़ ब्लॉक का उपयोग कर सकते हैं। .NET 4 के लिए, यह async targeting pack का उपयोग कर उपलब्ध है।

यदि आप .NET 4.0 पर हैं, तो सबसे सरल तरीका प्रत्येक निरंतरता में पूर्व कार्य से Task.Result तक पहुंचने के लिए है, या यदि परिणाम न लौटाता है, तो आप अपने नमूना कोड में Task.Wait() का उपयोग करें। हालांकि, आप AggregateException ऑब्जेक्ट्स के नेस्टेड पेड़ के साथ समाप्त होने की संभावना है, जिसे आपको 'असली' अपवाद प्राप्त करने के लिए बाद में सुलझाने की आवश्यकता होगी। (फिर से, .NET 4.5 यह आसान बनाता है। Task.Result फेंकता है जबकि AggregateException, Task.GetAwaiter().GetResult() -which है अन्यथा बराबर-फेंकता अंतर्निहित अपवाद।)

दोहराना करने के लिए कि यह वास्तव में एक छोटी सी समस्या नहीं है, आप एरिक Lippert के में रुचि हो सकती सी # 5 एसिंक कोड here और here में अपवाद हैंडलिंग पर आलेख।

+0

'टास्क.गेटवाइटर() के लिए बहुत बहुत धन्यवाद। GetResult() '! – torvin

0

जिस दृष्टिकोण का हम अब openstack.net एसडीके में उपयोग करते हैं वह CoreTaskExtensions.cs में विस्तार विधियां है।

तरीकों दो प्रकार के होते:

  • Then: निरंतरता एक Task देता है, और Unwrap() स्वचालित रूप से कहा जाता है।
  • Select: निरंतरता एक वस्तु देता है, और Unwrap() पर कोई कॉल नहीं होता है। यह विधि केवल हल्के निरंतरता के लिए है क्योंकि यह हमेशा TaskContinuationOptions.ExecuteSynchronously निर्दिष्ट करती है।

इन विधियों निम्नलिखित फायदे हैं:

  1. निरंतरता विधि बुला से बचा जाता है जब पूर्ववर्ती गलती या रद्द कर दिया गया है।
  2. इसके बजाए, पूर्ववर्ती का परिणाम AggregateException की कई परतों में अपवाद को लपेटने के बिना, जंजीर ऑपरेशन (सटीक रूप से अपवाद जानकारी को संरक्षित करना) का परिणाम बन जाता है।
  3. कॉलर्स को निरंतरता विधियों को लिखने की अनुमति देता है जो दोषपूर्ण पूर्ववर्तियों का समर्थन करते हैं, इस मामले में केवल निरंतर कार्य को निरंतर छोड़ दिया जाता है (विस्तार विधियों के लिए supportsErrors=true निर्दिष्ट करें)।
  4. जारी रखने वाले Task को निरंतर निष्पादित किया जाता है और Unwrap() आपके लिए बुलाया जाता है।

निम्नलिखित तुलना से पता चलता है कि कैसे हम CloudAutoScaleProvider.cs के लिए यह परिवर्तन, जो मूल रूप ContinueWith और Unwrap बड़े पैमाने पर इस्तेमाल लागू:
https://github.com/openstacknetsdk/openstack.net/compare/3ae981e9...299b9f67#diff-3

संबंधित मुद्दे

 संबंधित मुद्दे