Async partial void MyPartialMethod()危险吗?

时间:2016-09-07 05:57:00

标签: c# asynchronous async-await

我已经看到很多关于编写代码的警告,例如......

public async void MyDangerousMethodWhichCouldCrashMyApp...

我已经读过它与Eventhandlers的确定,因为它们必须返回void。但是partial methods也必须返回void。您可以拥有以下代码......

static void Main(string[] args)
{
    MainAsync().Wait();
    Console.ReadLine();
}

async static Task MainAsync()
{
    MyCodeGeneratedClass c = new MyCodeGeneratedClass();
    try
    {
        await c.MyCodeGeneratedMethod();
    }
    catch(Exception ex)
    {
        Console.WriteLine(ex.Message);
    }
}

public partial class MyCodeGeneratedClass
{
    public async Task MyCodeGeneratedMethod()
    {
        HttpClient client = new HttpClient();
        Console.WriteLine(await client.GetStringAsync("http://msdn.microsoft.com"));
        MyCustomCode();
    }

    partial void MyCustomCode();
}

然后实现为......

partial class MyCodeGeneratedClass
{
    async partial void MyCustomCode()
    {
        HttpClient client = new HttpClient();
        Console.WriteLine(await client.GetStringAsync("http://msdn.microsoft.com"));
        throw new Exception("Boom");
    }
}

但是,如果MyCustomCode的实现遇到异常,应用程序会发生什么?

如果它不合适,鉴于async / await的流行程度如何,这是否意味着部分方法基本上已经过时了?代码生成系统是否应该停止暴露部分方法以支持事件,或者更好的是仍然在基类中清空受保护的虚拟方法?即。

protected virtual Task MyCustomCode(T foo)
{
    return Task.FromResult(0);
}
编辑:好的,所以我已对代码进行了多次更新。在我编写的原始伪代码之后没有得到好评。我认为上面的代码证明了async partial void MyPartialMethod肯定是一个问题,因为对MyCodeGeneratedMethod的调用似乎确实打倒了app域,尽管试图捕获调用。我只是想知道是否有更好的选择,而不是转向受保护的虚拟基类方法。

2 个答案:

答案 0 :(得分:7)

  

但是,如果MyCustomCode的实现遇到异常,应用程序会发生什么?

async void方法的语义是直接在方法开头的当前SynchronizationContext引发异常。关于async void的这个和其他有趣的事实包含在我的async best practices文章中。

  

这是否意味着部分方法基本上已经过时了?

与事件处理程序一样过时。所以,不,不是真的。但是,它们没有更新以允许返回类型为Task,因此它们似乎是一种语言功能,并未使用其他语言进行主动更新。< / p>

  

代码生成系统是否应该停止公开部分方法以支持事件,或者更好的是仍然在基类中清空受保护的虚拟方法?

事件根本不会改变这一点;它们仍然使用async void实现。

如果&#34;钩子&#34;需要异步,然后更改所有生成的代码,因为它也必须都是异步的。

如果生成的代码需要来自部分方法的某些结果,则异步部分方法才会起作用。实现必须执行一些异步工作才能生成该结果。根据我的经验,部分方法在概念上更像是事件,因此async void是可以接受的。

答案 1 :(得分:1)

对于使用Xamarin的人来说,这似乎是一个大问题,因为在这个帖子中可以看到,生成代码有很多钩子实现为部分方法......

https://forums.xamarin.com/discussion/2766/cannot-await-in-an-async-partial-method

正如我在那里发布的那样,我建议任何考虑在部分方法中编写异步代码的人将其异步代码包装在try catch中,如下所示......

public partial class MyCodeGeneratedClass
{
    public async Task MyCodeGeneratedMethod()
    {
        HttpClient client = new HttpClient();
        Console.WriteLine(await client.GetStringAsync("http://msdn.microsoft.com"));
        MyCustomCode();
    }

    partial void MyCustomCode();
}

partial class MyCodeGeneratedClass
{
    async partial void MyCustomCode()
    {
        try
        {
            await MyCustomCodeAsync();
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    protected async Task MyCustomCodeAsync()
    {
        HttpClient client = new HttpClient();
        Console.WriteLine(await client.GetStringAsync("http://msdn.microsoft.com"));

        throw new Exception("Boom");
    }
}

尝试并捕捉异步任务方法应该保护应用程序域。此外,如果/当Microsoft improve partial methods时,它也可能更容易重构您的代码。

由于我可以控制在我的项目中生成代码的脚本,所以我选择不在可能存在I / O且异步的情况下暴露部分方法理想的,而是在基类中提供空的受保护的虚拟Task方法。此外,生成的代码需要能够等待CustomCode方法,似乎没有办法使用异步部分方法。