2015-11-26 12 views
8

मैं इस विधिपरिवर्तित कार्रवाई विधि async कार्रवाई विधि कॉल करने के लिए कॉल

public void Execute(Action action) 
{ 
    try 
    { 
     action(); 
    } 
    finally 
    { 
    } 
} 

है और मैं एक async विधि कॉल करने के लिए यह इस एक

public async Task ExecuteAsync(Action action) 
{ 
    try 
    { 
     await action(); 
    } 
    finally 
    { 
    } 
} 

कोड के साथ समस्या की तरह बदलने की आवश्यकता उपरोक्त यह है कि संकलक निम्नलिखित त्रुटि

'प्रतीक्षा' ऑपरेटर का उपयोग केवल एसिंक लैम्ब्डाके भीतर किया जा सकता है 0 अभिव्यक्ति। इस लैम्ब्डा अभिव्यक्ति को 'async' संशोधक के साथ चिह्नित करने पर विचार करें।

+1

देखो: http://stackoverflow.com/questions/20593501/the-await-operator-can-only-be-used-in-async-lambda-expression –

+0

आखिर में क्या कर रहा है? –

+0

@ जेली मैं जो लिंक करना चाहता हूं उसे लागू करने के लिए उस लिंक का अनुसरण करूंगा। धन्यवाद – vcRobe

उत्तर

3

इस प्रयास करें:

public async void ExecuteAsync(Action action) 
{ 
    await Task.Run(action); 
} 

Task.Run() का उपयोग करते हुए एक अलग कार्य पर अपनी गतिविधि का चलाकर एक awaitable पैदा करता है। और यह भी ध्यान में रखें कि "प्रतीक्षा करने योग्य" पर अपवादों को संभालने से intended पर काम नहीं होता है।

बेहतर रैप कि action() उस रैपर पर Task.Run() को पकड़ने का प्रयास करें।

+2

मुझे लगता है कि कार्य.रुन() से बचा जाना चाहिए क्योंकि यह ** हमेशा ** अलग थ्रेड में चलाएगा। यही कारण है कि मैं async/प्रतीक्षा का उपयोग करने की कोशिश कर रहा हूँ। – vcRobe

+0

@vcRobe: तो आप इसे async के रूप में चलाने के लिए चाहते हैं लेकिन एक ही धागे पर? –

+0

@ टामासनोनट: अधिमानतः – vcRobe

13

यदि आप एक प्रतिनिधि पर await चाहते हैं, तो यह Func<Task> या Func<Task<T>> टाइप करना होगा। एक Actionvoid Action() नामित विधि के बराबर है। आप void पर इंतजार नहीं कर सकते हैं, फिर भी आप का इंतजार कर सकते हैं Task Func() या Task<T> Func:

public async Task ExecuteAsync(Func<Task> func) 
{ 
    try 
    { 
     await func(); 
    } 
    finally 
    { 
    } 
} 

यह नहीं किया जा सकता है, इसका मतलब है कि आंतरिक रूप से विधि वास्तव में अतुल्यकालिक नहीं है, और क्या आप वास्तव में क्या करना चाहते हैं थ्रेड-पूल थ्रेड पर सिंक्रोनस प्रतिनिधि को निष्पादित करता है, जो एक अलग मामला है, और वास्तव में कुछ असंकालिक रूप से निष्पादित नहीं कर रहा है। उस स्थिति में, Task.Run के साथ कॉल को लपेटना पर्याप्त होगा। क्योंकि तुम कहते हो finally महत्वपूर्ण नहीं है

public void Execute(Action action) 
{ 
    action(); 
} 

:

+2

हां यह भी भ्रमित करता है कि लोगों को यह तथ्य है कि सी # कंपाइलर 'async() => {await ...}' के प्रकार को 'एक्शन' या 'Func ' के प्रकार की अनुमति देता है। और यदि लोग इसे 'एक्शन' के साथ टाइप करना चुनते हैं तो उन्हें उस पर 'प्रतीक्षा' करने में कठिनाई होती है। अगर वे बुद्धिमानी से 'Func ' का उपयोग करना चुनते हैं, तो अब यह प्रतीक्षा कर रहा है। दूसरों के बीच 'Func ' पर 'एक्शन'' का उपयोग करने के बारे में यह एक अच्छी बात है। मुझे वास्तव में यह पसंद नहीं है कि संकलक स्पष्टता के लिए इस मामले में 'एक्शन' प्रकार का प्रकार बनने की अनुमति देता है। – KFL

+0

@ केएफएल कई लोग समान महसूस करते हैं। यह 'एक्शन' पर काम करने का कारण यह है क्योंकि इस सुविधा के डिजाइनर इसे ईवेंट हैंडलर के साथ संगत बनाना चाहते थे जो स्वाभाविक रूप से' शून्य 'वापसी विधियां हैं। –

0

के लिए नीचे अपने प्रारंभिक बिंदु को आसान बनाने में करते हैं।

मान्य लेकिन व्यर्थ:

public async Task ExecuteAsync(Action action) 
{ 
    action(); 
} 

यह कर के रूप में बहुत ज्यादा एक ही हो जाएगा:

public Task ExecuteAsync(Action action) 
{ 
    action(); 
    return Task.FromResult(0); 
} 

है यही कारण है, यह क्या गैर async कर रहा था करूँगा, और फिर वापसी एक "पूरा" कार्य इसलिए कुछ भी प्राप्त नहीं हुआ है। यह ध्यान देने योग्य है हालांकि यह गैर-async से async में जाने में अक्सर एक वैध अंश-मार्ग बिंदु है।

बेहतर:

public async Task ExecuteAsync(Action action) 
{ 
    await Task.Run(() => action()); 
} 

जो इस मामले में, यह है, क्योंकि एक भी शून्य-लौटने कॉल करने के लिए सरल किया जा सकता:

public async Task ExecuteAsync(Action action) 
{ 
    await Task.Run(action); 
} 

चाहे ऐसा करने के लायक है या नहीं अलग बात है। यह वर्तमान धागे को इस्तेमाल होने से मुक्त करता है, लेकिन काम करने के लिए दूसरे धागे में स्थानांतरित होता है। अगर हम इसे इसके परिणाम के इंतजार के लिए इंतजार कर रहे हैं तो इसे तब भी कहा जा सकता है जब हम गैर-एसिंक संस्करण को कॉल कर सकते हैं और इसके साथ किया जा सकता है। यदि हम कॉलर में WaitAll कर रहे हैं, या ऐसा कुछ और जो इससे लाभान्वित है, तो यह वास्तव में उपयोगी हो सकता है।

संभावित ज्यादा बेहतर यह है:

public async Task ExecuteAsync(Action action) 
{ 
    await actionAsync(); 
} 

यहाँ वहाँ विधि हम बुला रहे हैं की एक Async संस्करण है, तो हम इस बात का उपयोग करने के लिए बदल जाते हैं। अब, यह उपर्युक्त जैसा ही हो सकता है यदि actionAsync बस थ्रेड को स्पिन करता है या थ्रेड पूल का उपयोग करता है। यदि actionAsync कुछ एसिंक्रोनस I/O का उपयोग करता है तो इसके लिए बहुत बड़ा लाभ होता है।

नोट इस मामले में हम हो सकता है कि सिर्फ पूंछ तथाकथित टास्क हम पाते हैं:

public Task ExecuteAsync(Action action) 
{ 
    return actionAsync(); 
} 

हालांकि, कि नहीं एक ही अगर हम कुछ हमारे विधि के भीतर एक await के बाद किया की जरूरत होगी। उदाहरण के लिए:

public void Execute(Action action) 
{ 
    action(); 
    otherAction(); 
} 

बनने के लिए होगा:

public async Task Exectute(Action action) 
{ 
    await actionAsync(); 
    await otherActionAsync(); 
} 

या अगर otherAction कोई async संस्करण था: यहाँ जवाब में

public async Task Exectute(Action action) 
{ 
    await actionAsync(); 
    otherAction(); 
} 
+0

जब दो एसिंक विधियां होती हैं तो हम कार्य का उपयोग कर सकते हैं। जब सभी() –

+1

@ टामासऑनट नहीं, अगर आपको किसी के शुरू होने से पहले पूरा होने की आवश्यकता है। –

+0

हाँ, अच्छा बिंदु। –

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