使接口实现异步

Mor*_*iya 103 c# asynchronous async-await

我目前正在尝试使用一些异步方法来创建我的应用程序.我的所有IO都是通过接口的显式实现完成的,我对如何使操作异步感到困惑.

在我看到的情况下,我在实现中有两个选项:

interface IIO
{
    void DoOperation();
}
Run Code Online (Sandbox Code Playgroud)

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
}
Run Code Online (Sandbox Code Playgroud)

选项2: 显式实现异步并等待隐式实现中的任务.

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

    #region IIOAsync Members

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

    #endregion
}
Run Code Online (Sandbox Code Playgroud)

这些实现中的一个是否比另一个更好,还是有另一种方法可以解决这个问题?

svi*_*ick 208

这些选项都不正确.您正在尝试异步实现同步接口.不要那样做.问题是DoOperation()返回时,操作还不完整.更糟糕的是,如果在操作期间发生异常(这在IO操作中非常常见),则用户将没有机会处理该异常.

您需要做的是修改接口,使其成为异步:

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

class IOImplementation : IIO
{
    public async Task DoOperationAsync()
    {
        // perform the operation here
    }
}
Run Code Online (Sandbox Code Playgroud)

这样,用户将看到操作是async并且他们将能够进行操作await.这也几乎迫使你的代码用户切换到async,但这是不可避免的.

另外,我假设StartNew()在您的实现中使用只是一个示例,您不应该需要实现异步IO.(而且new Task()更差,甚至不会工作,因为你不知道Start()Task.)

  • 然后,使代码异步没有多大意义.请参阅文章[*我应该为同步方法公开异步包装器吗?*](http://blogs.msdn.com/b/pfxteam/archive/2012/03/24/10287244.aspx) (4认同)
  • @Animal Explicit 实现看起来和往常一样(只需添加`async`):`async Task IIO.DoOperationAsync()`。你的意思是你在哪里“等待”返回的“任务”?无论您在哪里调用“DoOperationAsync()”。 (2认同)

Dim*_*ima 15

更好的解决方案是为异步操作引入另一个接口.新接口必须从原始接口继承.

例:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

PS重新设计你的异步操作,所以他们返回Task而不是void,除非你真的必须返回void.

  • 为什么不`GetAwaiter().GetResult()`而不是`Wait()`?这样你就不需要解压缩`AggregateException`来获取内部异常. (5认同)
  • 您不应在代码中使用 GetAwaiter 和 GetResult()。它仅适用于编译器:[TaskAwaiter Struct](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.taskawaiter?view=net-5.0) (2认同)