2013-04-26 10 views
12

से मैं में देखा है कई coding examples, साथ ही, क्या मैं इस SO question से समझ सकता हूँ मैं TaskCompletionSourceवापसी टास्क टास्क <TResult> के बजाय TaskCompletionSource

से
(i.e., Return Task and not Task<TResult> from the method UploadFilesAsync) 

एक गैर सामान्य कार्य वापस जाने के लिए सक्षम होना चाहिए फिर भी निम्न कोड:

public async Task UploadFilesAsync(string fileAPath, string fileBPath) 
{ 
    var tcs = new TaskCompletionSource<Object>(); 

    //logic to process files 

    try 
    { 
     await Task.WhenAll(uploadFileAAsync(fileAPath), 
         uploadFileBAsync(fileBPath)); 
     tcs.TrySetResult(null); 
    } 
    catch (Exception e) 
    { 
     tcs.SetException(e); 
    } 
    finally 
    { 
     //logic to clean up files 
    } 
    return tcs.Task; 
} 

निम्न सिंटैक्स त्रुटि का उत्पादन

'UploadFilesAsync(string, string)' is an async method that returns 'Task', 
a return keyword must not be followed by an object expression. 
Did you intend to return 'Task<T>'? 

मैं .NET 4.5 को लक्षित कर रहा हूं। मुझे पता है कि यह कार्य (ऑब्जेक्ट) को वापस करने के लिए काम कर सकता है लेकिन इससे एपीआई को "गंदा" लगता है। क्या यह कार्य (ऑब्जेक्ट) को वापस करने के लिए अभ्यास पसंद करता है या क्या कार्य को वापस करना संभव है (कोड में दिखाए गए गैर-जेनेरिक)?

उत्तर

25

मैं इसे वापस करने के लिए टास्क (वस्तु का) काम कर सकते हैं

ठीक है, कि क्या आप इसे करने के लिए उम्मीद से काम नहीं चलेगा पता है।

समस्या यह है कि आप एक कार्य वापस करने की कोशिश कर रहे हैं ... और एक async विधि स्वचालित रूप से किसी अन्य कार्य में वापसी मान को लपेटता है। यह स्पष्ट नहीं है कि आप ईमानदार होने के लिए यहां एसिंक विधि का उपयोग क्यों कर रहे हैं। क्यों न केवल इसे लिखें:

public Task UploadFilesAsync(string fileAPath, string fileBPath) 
{ 
    return Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath)); 
} 

क्या आप जो चाहते हैं वह नहीं करते हैं? आप बस एक कार्य चाहते हैं जो "उपपरिवर्तन" दोनों पूरा हो गया है, है ना? यह ठीक है Task.WhenAll रिटर्न। आपकी विधि अभी भी गैर-अवरुद्ध है - यह तब तक इंतजार नहीं करेगी जब तक कि रिटर्न पूरा होने से पहले पूरा नहीं हो जाता है। यह सिर्फ इतना है कि आप इस तथ्य का उपयोग कर रहे हैं कि Task.WhenAll एक एसिंक विधि के बजाय, इसे प्राप्त करने के लिए गैर-अवरुद्ध है।

संपादित करें: ध्यान दें कि यदि आप उस विधि में कुछ और ही रूप में अच्छी तरह करना चाहता था, आप इसे एक async विधि अपने आप को TaskCompletionSource का उपयोग किए बिना कर सकता है:

public async Task UploadFilesAsync(string fileAPath, string fileBPath) 
{ 
    // Upload the files 
    await Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath)); 
    await SomethingElseAsync(); 
    MaybeDoSomethingCheap(); 
} 

नोट है कि भले ही async विधि यहाँ Task रिटर्न , आपके पास रिटर्न वैल्यू नहीं है - एसिंक/प्रतीक्षा मशीनरी आपके लिए यह सब संभालती है, एक कार्य लौटाता है जो पूरा हो जाएगा जब MaybeDoSomethingCheap() समाप्त हो गया है, या अपवाद फेंकने पर गलती हो गई है।

+0

मुझे फ़ाइलों को अनजिप करना, अपलोड चलाने, और फिर अनपॅक की गई फ़ाइलों को हटाना होगा।मैं चाहता था कि अपलोड एसिंक को चलाने के लिए और यही कारण है कि मैंने उन्हें taskcompletionsource में लपेट लिया ... या जैसा आपने सुझाव दिया था मैंने किया होगा। यह समझ में आता है कि एसिंक एक और कार्य में वापसी को लपेटता है (कोई आश्चर्य नहीं कि एसिंक/प्रतीक्षा के साथ एक कामकाजी उदाहरण देखना मुश्किल था)। धन्यवाद! –

+1

@ जोनाथन हैरिसन: बस जांचने के लिए - क्या आप समझते हैं कि आप * सुझाव क्यों कर सकते हैं जैसा कि मैंने सुझाव दिया है, और यह अभी भी async है? मैं एक और बिट जोड़ूंगा जो मदद कर सकता है ... –

+0

संपादन करने के लिए बहुत बहुत धन्यवाद। उस अवधारणा ने शुरुआत में क्लिक नहीं किया ... यह सुंदर है कि async/await वास्तव में इस तरह एक async शून्य विधि को संभालती है। –

2

जहां तक ​​मुझे पता है कि TaskCompletionSource<T> पर नियोजित करते समय Task ऑब्जेक्ट को वापस करने का कोई सीधा तरीका नहीं है।

आम तौर पर मैं इन परिस्थितियों में Task<bool> प्रकार ऑब्जेक्ट वापस करना पसंद करता हूं। लेकिन आप सही हैं कि, सामान्य प्रकार की ऑब्जेक्ट को वापस करने से कोई अर्थ नहीं होता है कि फ़ंक्शन का रिटर्न मान उपयोग करने योग्य नहीं है।

लेकिन वास्तव में आपको TaskCompletionSource बनाने की आवश्यकता नहीं है क्योंकि आपके पास await फ़ंक्शन के अंदर कीवर्ड है। TaskCompletionSource आमतौर पर एक सिंक्रोनस फ़ंक्शन को एसिंक्रोनस में परिवर्तित करने के लिए उपयोग किया जाता है। चूंकि आप पहले से ही एसिंक्रोनस फ़ंक्शन को कॉल कर रहे हैं (और वास्तव में यह एकमात्र कार्यक्षमता के रूप में प्रतीत होता है) आपको TaskCompletionSource बनाने की आवश्यकता नहीं है।

public async Task UploadFilesAsync(string fileAPath, string fileBPath) 
{ 
     return await Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath)); 
} 
+0

प्रतिक्रिया के लिए धन्यवाद और जो आपने लिखा है वह समझ में आता है। जॉन स्कीट को मेरी टिप्पणी देखें कि मैंने टास्क कॉम्प्लेशनसोर्स का उपयोग क्यों किया। –

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