避免覆盖中的异步问题

时间:2013-11-01 18:08:20

标签: c# .net asynchronous async-await

我为我正在开发的程序开发了一种简单的插件框架,作为其中的一部分,我有抽象基类,插件是从中派生出来的。例如:

public abstract class Plugin
{
    public Task StartAsync()
    {
        Task.Run(Start);
    }

    protected abstract void Start();
}

问题在于,我真的希望能够等待StartAsync并在插件中完成所有内容(尽可能完成);很大程度上,我可以将所有内容包装在try-catch中,并避免插件取消我的应用程序(我意识到我应该使用应用程序域,如果必须,我会)。

在我使用异步Start方法定义插件之前,这一切都正常工作:

public class MyPlugin
{
    protected override async void Start()
    {
        // await some awaitable stuff
    }
}

当然,我的抽象基类不等待Start(因为它不知道它在编译时会异步)所以如果MyPlugin抛出异常,框架就没有机会捕获它。很明显,如果插件实现者做了一些非同步的异步,这也是正确的,但这似乎是一种非常简单的方法,只需在方法签名中添加异步,就可以自己动手。我意识到要求“等待等待”操作员是不合理的,但我想知道是否有人对如何摆脱这个问题有任何想法(或者它根本不是问题而且我是不合理的。)

这就是我想要在脑海中看到的内容:

public abstract class Plugin
{
    public Task StartAsync()
    {
        Task.Run(() => awaitif Start());
    }

    protected abstract void Start();
}

最后,我宁愿不要使用Start async或返回一个Task,因为大多数插件可能都是简单和同步的。

1 个答案:

答案 0 :(得分:2)

Task - 接口中的返回方法与IDisposable在设计上非常相似。

  

我宁愿不要使用Start async或返回一个Task,因为大多数插件可能都是简单和同步的。

事实是,某些的插件是异步的;因此,您应该有一个异步签名。在实现结束时,同步插件很容易return Task.FromResult(0)

考虑与IDisposable的相似性:如果你的插件的某些是一次性的,你仍然应该从IDisposable派生出来并且让非一次性插件实现空{ {1}}。