इंटरफ़ेस कार्यान्वयन को async बनाना


116

मैं वर्तमान में कुछ Async विधियों का उपयोग करके अपना एप्लिकेशन बनाने का प्रयास कर रहा हूं। मेरे सभी IO को एक इंटरफ़ेस के स्पष्ट कार्यान्वयन के माध्यम से किया जाता है और मैं थोड़ा असमंजस में हूं कि ऑपरेशन को कैसे किया जाए।

जैसा कि मैं चीजों को देखता हूं मेरे पास कार्यान्वयन में दो विकल्प हैं:

interface IIO
{
    void DoOperation();
}

OPTION1: एक अंतर्निहित कार्यान्वयन एस्किंस करें और अंतर्निहित कार्यान्वयन में परिणाम का इंतजार करें।

class IOImplementation : IIO
{

     async void DoOperation()
    {
        await Task.Factory.StartNew(() =>
            {
                //WRITING A FILE OR SOME SUCH THINGAMAGIG
            });
    }

    #region IIO Members

    void IIO.DoOperation()
    {
        DoOperation();
    }

    #endregion
}

OPTION2: स्पष्ट कार्यान्वयन async करें और अंतर्निहित कार्यान्वयन से कार्य का इंतजार करें।

class IOAsyncImplementation : IIO
{
    private Task DoOperationAsync()
    {
        return new Task(() =>
            {
                //DO ALL THE HEAVY LIFTING!!!
            });
    }

    #region IIOAsync Members

    async void IIO.DoOperation()
    {
        await DoOperationAsync();
    }

    #endregion
}

क्या इनमें से एक क्रियान्वयन दूसरे की तुलना में बेहतर है या क्या कोई और तरीका है जो मैं नहीं सोच रहा हूं?

जवाबों:


231

इनमें से कोई भी विकल्प सही नहीं है। आप अतुल्यकालिक रूप से एक तुल्यकालिक इंटरफ़ेस को लागू करने की कोशिश कर रहे हैं। ऐसा मत करो। समस्या यह है कि जब DoOperation()रिटर्न, ऑपरेशन अभी तक पूरा नहीं होगा। इससे भी बदतर, अगर ऑपरेशन के दौरान एक अपवाद होता है (जो आईओ संचालन के साथ बहुत आम है), तो उपयोगकर्ता को उस अपवाद से निपटने का मौका नहीं मिलेगा।

इंटरफ़ेस को संशोधित करने के लिए आपको क्या करने की आवश्यकता है , ताकि यह अतुल्यकालिक हो:

interface IIO
{
    Task DoOperationAsync(); // note: no async here
}

class IOImplementation : IIO
{
    public async Task DoOperationAsync()
    {
        // perform the operation here
    }
}

इस तरह, उपयोगकर्ता देखेगा कि ऑपरेशन है asyncऔर वे awaitइसे करने में सक्षम होंगे । यह आपके कोड के उपयोगकर्ताओं को स्विच करने के लिए बहुत अधिक मजबूर करता है async, लेकिन यह अपरिहार्य है।

इसके अलावा, मुझे लगता है StartNew()कि आपके कार्यान्वयन में उपयोग केवल एक उदाहरण है, आपको अतुल्यकालिक आईओ को लागू करने की आवश्यकता नहीं होनी चाहिए। (और new Task()भी बदतर है, यह भी काम नहीं करेगा, क्योंकि आप नहीं Start()हैं Task।)


एक स्पष्ट कार्यान्वयन के साथ यह कैसे दिखेगा? इसके अलावा, आप इस कार्यान्वयन की प्रतीक्षा कहाँ करते हैं?
मोरिया

1
@ अनिमल स्पष्ट कार्यान्वयन हमेशा (बस जोड़ async) के समान होगा async Task IIO.DoOperationAsync():। और क्या आपका मतलब है कि आप कहां awaitलौटे हैं Task? जिधर भी बुलाओ DoOperationAsync()
svick

मूल रूप से मुझे लगता है कि मैं अपने सवाल का जवाब "मैं कहां इंतजार कर सकता हूं?" यदि मैं एसिंक्स पद्धति के अंदर प्रतीक्षा नहीं करता हूं तो मुझे संकलन चेतावनी मिलती है।
मोरिया

1
आदर्श रूप में, आपको IO कोड को लपेटने की आवश्यकता नहीं होनी चाहिए Task.Run(), कि IO कोड स्वयं अतुल्यकालिक होना चाहिए और आप इसे awaitसीधे कर सकते हैं। जैसे line = await streamReader.ReadLineAsync()
13

4
फिर आपके कोड को एसिंक्रोनस बनाने में बहुत ज्यादा फायदा नहीं है। लेख देखें क्या मुझे तुल्यकालिक विधियों के लिए अतुल्यकालिक आवरणों को उजागर करना चाहिए?
svick

19

बेहतर समाधान के लिए एक और इंटरफ़ेस है async संचालन। नए इंटरफ़ेस को मूल इंटरफ़ेस से इनहेरिट करना होगा।

उदाहरण:

interface IIO
{
    void DoOperation();
}

interface IIOAsync : IIO
{
    Task DoOperationAsync();
}


class ClsAsync : IIOAsync
{
    public void DoOperation()
    {
        DoOperationAsync().GetAwaiter().GetResult();
    }

    public async Task DoOperationAsync()
    {
        //just an async code demo
        await Task.Delay(1000);
    }
}


class Program
{
    static void Main(string[] args)
    {
        IIOAsync asAsync = new ClsAsync();
        IIO asSync = asAsync;

        Console.WriteLine(DateTime.Now.Second);

        asAsync.DoOperation();
        Console.WriteLine("After call to sync func using Async iface: {0}", 
            DateTime.Now.Second);

        asAsync.DoOperationAsync().GetAwaiter().GetResult();
        Console.WriteLine("After call to async func using Async iface: {0}", 
            DateTime.Now.Second);

        asSync.DoOperation();
        Console.WriteLine("After call to sync func using Sync iface: {0}", 
            DateTime.Now.Second);

        Console.ReadKey(true);
    }
}

PS अपने async ऑपरेशंस को फिर से डिज़ाइन करें ताकि वे शून्य के बजाय टास्क लौटाएं, जब तक कि आपको वास्तव में शून्य वापस नहीं करना चाहिए।


5
GetAwaiter().GetResult()इसके बजाय क्यों नहीं Wait()? इस तरह आप AggregateExceptionआंतरिक अपवाद लाने के लिए एक खोलना नहीं है।
टैगक

एक भिन्नता कई (संभवतः स्पष्ट) इंटरफेस को लागू करने वाले वर्ग पर निर्भर है class Impl : IIO, IIOAsync:। IIO और IIOAsync स्वयं, हालांकि, विभिन्न अनुबंध हैं जो 'पुराने अनुबंधों' को नए कोड में खींचने से बच सकते हैं। var c = new Impl(); IIOAsync asAsync = c; IIO asSync = c
user2864740
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.