c# - चेतावनी इस कॉल की प्रतीक्षा नहीं है, वर्तमान विधि का निष्पादन जारी है




async-await (6)

इस चेतावनी पर माइक्रोसॉफ्ट आलेख के मुताबिक, आप इसे लौटाए गए कार्य को एक चर में असाइन करके हल कर सकते हैं। नीचे माइक्रोसॉफ्ट उदाहरण में दिए गए कोड का अनुवाद है:

    // To suppress the warning without awaiting, you can assign the 
    // returned task to a variable. The assignment doesn't change how
    // the program runs. However, the recommended practice is always to
    // await a call to an async method.
    // Replace Call #1 with the following line.
    Task delayTask = CalledMethodAsync(delay);

ध्यान दें कि ऐसा करने से रीशेर्पर में "स्थानीय चर का कभी भी उपयोग नहीं किया जाएगा" संदेश होगा।

बस वीएस2012 मिला और एसिंक पर एक संभाल पाने की कोशिश कर रहा है।

मान लें कि मेरे पास एक तरीका है जो अवरुद्ध स्रोत से कुछ मूल्य प्राप्त करता है। मैं ब्लॉक करने के लिए विधि के कॉलर नहीं चाहता। मैं कॉलबैक लेने के लिए विधि लिख सकता हूं, जब मूल्य आता है, लेकिन जब से मैं सी # 5 का उपयोग कर रहा हूं, तो मैं विधि एसिंक बनाने का फैसला करता हूं ताकि कॉलर्स को कॉलबैक से निपटने की आवश्यकता न हो:

// contrived example (edited in response to Servy's comment)
public static Task<string> PromptForStringAsync(string prompt)
{
    return Task.Factory.StartNew(() => {
        Console.Write(prompt);
        return Console.ReadLine();
    });
}

यहां एक उदाहरण विधि है जो इसे कॉल करती है। यदि PromptForStringAsync async नहीं था, तो इस विधि को कॉलबैक के भीतर कॉलबैक घोंसले की आवश्यकता होगी। एसिंक के साथ, मुझे अपनी विधि को इस बहुत ही प्राकृतिक तरीके से लिखना है:

public static async Task GetNameAsync()
{
    string firstname = await PromptForStringAsync("Enter your first name: ");
    Console.WriteLine("Welcome {0}.", firstname);

    string lastname = await PromptForStringAsync("Enter your last name: ");
    Console.WriteLine("Name saved as '{0} {1}'.", firstname, lastname);
}

अब तक सब ठीक है। समस्या यह है कि जब मैं GetNameAsync को कॉल करता हूं:

public static void DoStuff()
{
    GetNameAsync();
    MainWorkOfApplicationIDontWantBlocked();
}

GetNameAsync का पूरा बिंदु यह है कि यह GetNameAsync है। मैं इसे अवरुद्ध नहीं करना चाहता , क्योंकि मैं मेनवॉर्क्सऑफ एप्लिकेशन पर वापस जाना चाहता हूं, एंटएपब्लॉकब्लॉक एएसएपी और GetNameAsync पृष्ठभूमि में अपनी चीज करने देता हूं। हालांकि, इसे इस तरह से कॉल करने से मुझे GetNameAsync लाइन पर एक कंपाइलर चेतावनी GetNameAsync :

Warning 1   Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the 'await' operator to the result of the call.

मुझे पूरी तरह से पता है कि कॉल पूरा होने से पहले मौजूदा विधि का निष्पादन जारी है "। यह असीमित कोड का मुद्दा है, है ना?

मैं चेतावनियों के बिना संकलित करने के लिए अपना कोड पसंद करता हूं, लेकिन यहां "ठीक" करने के लिए कुछ भी नहीं है क्योंकि कोड ठीक वही कर रहा है जो मैं करना चाहता हूं। मैं GetNameAsync के वापसी मूल्य को संग्रहीत करके चेतावनी से छुटकारा पा सकता GetNameAsync :

public static void DoStuff()
{
    var result = GetNameAsync(); // supress warning
    MainWorkOfApplicationIDontWantBlocked();
}

लेकिन अब मेरे पास अधूरा कोड है। विजुअल स्टूडियो को यह समझने लगता है कि मुझे इस अनावश्यक कोड को लिखने के लिए मजबूर होना पड़ा, क्योंकि यह सामान्य "मूल्य कभी भी इस्तेमाल नहीं किया गया" चेतावनी दबाता है।

मैं GetNameAsync को एक विधि में लपेटकर चेतावनी से छुटकारा पा सकता हूं जो async नहीं है:

    public static Task GetNameWrapper()
    {
        return GetNameAsync();
    }

लेकिन यह और भी अधिक अनिवार्य कोड है। तो मुझे कोड लिखना है, मुझे अनावश्यक चेतावनी की आवश्यकता नहीं है या सहन नहीं है।

क्या एसिंक के मेरे उपयोग के बारे में कुछ है जो यहां गलत है?


एसिंक शून्य शून्य है!

शून्य लौटने और कार्य वापस करने के बीच क्या अंतर है? http://www.jaylee.org/post/2012/07/08/c-sharp-async-tips-and-tricks-part-2-async-void.aspx http://www.tonicodes.net/blog/why-you-should-almost-never-write-void-asynchronous-methods/

मेरा सुझाव है कि आप अज्ञात विधि के माध्यम से कार्य को स्पष्ट रूप से चलाते हैं ...

अर्थात

public static void DoStuff()
{
    Task.Run(async () => GetNameAsync());
    MainWorkOfApplicationIDontWantBlocked();
}

या यदि आप इसे अवरुद्ध करना चाहते हैं तो आप अनाम विधि पर प्रतीक्षा कर सकते हैं

public static void DoStuff()
{
    Task.Run(async () => await GetNameAsync());
    MainWorkOfApplicationThatWillBeBlocked();
}

हालांकि, अगर आपकी "GetNameAsync" विधि को यूआई या यहां तक ​​कि यूआई बाध्यता के साथ बातचीत करना है, (WINRT / MVVM, मैं आपको देख रहा हूं); तो यह थोड़ा funkier हो जाता है =)

आपको इस तरह यूआई प्रेषक के संदर्भ को पारित करने की आवश्यकता होगी ...

Task.Run(async () => await GetNameAsync(CoreApplication.MainView.CoreWindow.Dispatcher));

और फिर आपके एसिंक विधि में आपको अपने यूआई या यूआई बाध्य तत्वों के साथ बातचीत करने की आवश्यकता होगी सोचा कि प्रेषक ...

dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => {  this.UserName = userName; });

मैं इस चर्चा के लिए काफी देर हो चुकी हूं, लेकिन #pragma प्री-प्रोसेसर निर्देश का उपयोग करने का विकल्प भी है। मेरे यहां कुछ एसिंक कोड है और मैं स्पष्ट रूप से कुछ स्थितियों में इंतजार नहीं करना चाहता हूं, और मैं आपके बाकी हिस्सों की तरह चेतावनियों और अप्रयुक्त चर को नापसंद करता हूं:

#pragma warning disable 4014
SomeMethodAsync();
#pragma warning restore 4014

"4014" इस एमएसडीएन पृष्ठ से आता है: कंपाइलर चेतावनी (स्तर 1) CS4014

https://.com/a/12145047/928483 @ रायन-horath द्वारा चेतावनी / उत्तर भी देखें।

एक एसिंक कॉल के दौरान फेंकने वाले अपवादों का इंतजार नहीं किया जाएगा। इस चेतावनी से छुटकारा पाने के लिए, आपको एक चर में async कॉल का कार्य वापसी मान असाइन करना चाहिए। यह सुनिश्चित करता है कि आपके पास फेंकने वाले किसी अपवाद तक पहुंच है, जिसे रिटर्न वैल्यू में इंगित किया जाएगा।


मैं उन समाधानों का विशेष रूप से शौकीन नहीं हूं जो या तो एक अप्रयुक्त चर को कार्य सौंपते हैं, या शून्य लौटने के लिए विधि हस्ताक्षर बदलते हैं। पूर्व अनावश्यक, गैर-सहज ज्ञान युक्त कोड बनाता है, जबकि उत्तरार्द्ध संभव नहीं हो सकता है यदि आप इंटरफ़ेस को कार्यान्वित कर रहे हैं या उस फ़ंक्शन का एक और उपयोग है जहां आप लौटा कार्य का उपयोग करना चाहते हैं।

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

विस्तार विधि:

public static class TaskExtensions
{
    public static void DoNotAwait(this Task task) { }
}

उपयोग:

public static void DoStuff()
{
    GetNameAsync().DoNotAwait();
    MainWorkOfApplicationIDontWantBlocked();
}

जोड़ने के लिए संपादित: यह जोनाथन एलन के समाधान के समान है जहां विस्तार विधि पहले से शुरू नहीं होने पर कार्य शुरू कर देगी, लेकिन मैं एकल उद्देश्य के कार्यों को पसंद करता हूं ताकि कॉलर का इरादा पूरी तरह से स्पष्ट हो।


यह आपका सरलीकृत उदाहरण है जो अतिप्रवाह कोड का कारण बनता है। आम तौर पर आप प्रोग्राम में किसी बिंदु पर अवरुद्ध स्रोत से प्राप्त डेटा का उपयोग करना चाहते हैं, तो आप परिणाम वापस चाहते हैं ताकि डेटा प्राप्त करना संभव हो।

यदि आपके पास वास्तव में ऐसा कुछ है जो शेष कार्यक्रम से पूरी तरह से अलग होता है, तो एसिंक सही दृष्टिकोण नहीं होगा। बस उस कार्य के लिए एक नया धागा शुरू करें।


यहां, एक साधारण समाधान।

public static class TasksExtensions
{
    public static void RunAndForget(this Task task)
    {
    }
}

सादर





async-await