Создание асинхронных реализаций интерфейса


В настоящее время я пытаюсь сделать Мои приложения, используя некоторые асинхронные методы. Все мои IO выполняются через явные реализации интерфейса, и я немного смущен тем, как сделать операции асинхронными.

как я вижу, у меня есть два варианта реализации:

interface IIO
{
    void DoOperation();
}

OPTION1: Выполните неявную реализацию async и дождитесь результата в неявной реализации.

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: Сделать явным реализация асинхронна и ожидает задачи от неявной реализации.

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

    #region IIOAsync Members

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

    #endregion
}

является ли одна из этих реализаций лучше, чем другая, или есть другой способ пойти, о котором я не думаю?

2 80

2 ответа:

ни один из этих вариантов правильный. Вы пытаетесь реализовать синхронный интерфейс асинхронно. Не делай этого. Проблема в том, что когда 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() the Task.)

лучшим решением является введение другого интерфейса для асинхронных операций. Новый интерфейс должен наследовать от исходного интерфейса.

пример:

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);
    }
}

С. П. Перепроектируйте свои асинхронные операции, чтобы они возвращали Task вместо void, если вы действительно не должны возвращать void.