如何将部分方法变为异步方法

19
我有一个带有部分方法的生成代码。

I have a generated code with partial method

{
    ...
    partial void InterceptOperationCall(IOperationContext context);
    ...

    async Task SomeMethod()
    {
        InterceptOperationCall(cntx);
        await LongOperation(cntx);
    }
}

而且手写部分

{
    partial void InterceptOperationCall(IOperationContext context)
    {
    }
}

我需要在InterceptOperationCall内进行异步调用,有没有人知道绕过部分方法限制的方法?

换句话说: 我想要异步地执行InterceptOperationCall并在长时间操作之前保证,同时我还想选择在另一个文件中声明此方法的主体。

更新作为解决方法,我选择:

  • 不使用生成的部分方法存根,并使用动态代理(Castle.DynamicProxy)进行包装,并使用(Nito.AsyncEx)中的AsyncInterceptorBase进行拦截
  • 另一种选择是改写代码生成器

无论如何,我仍在寻找更好的解决方案,如果有人知道提供将异步调用与某些异步逻辑包装起来的其他方法,请帮助我。


如果您想了解异步部分方法的限制,可以在文档中找到它们。但是,如果您需要绕过部分方法的限制,则需要提供更多信息。 - Llazar
@Llazar,感谢您的关注,我添加了一些问题的细节,您能告诉我需要哪些信息吗? - gabba
1
@gabba,您是想要等待部分方法还是想要在部分方法中调用可等待函数?由于所示示例是void方法,因此我需要澄清。 - Nkosi
如果重写代码生成器是一个选项,那么我建议将其重写为更符合异步等待API的标准。 - Nkosi
@Nkosi,你能提供一些样例或者给个想法吗? - gabba
3个回答

1
你可以在实现部分方法时使用async关键字。
因此,
async partial void InterceptOperationCall(IOperationContext context) {

}

应该没有问题。


4
您是否可以在不了解特定代码上下文(无意冒犯)的情况下安全地建议使用 "async void"? - Kenneth K.
不是的...我以为用户不知道如何为自动生成的方法连接异步实现。然而,有一些需要注意的陷阱…… - Peter Schneider
1
@PeterSchneider,太好了!它可以编译和工作,但是InterceptOperationCall、LongOperation方法的执行顺序取决于竞争条件。你知道有什么方法可以使这个结构可等待吗? - gabba
2
@gabba 当然,你应该返回 async Task 而不是 async void(现在你看到了使用部分类和异步方法的问题)。你可能需要重新考虑你的设计,不再使用部分类。 - Scott Chamberlain
@ScottChamberlain,我不得不使用部分代码,因为需要使用现有的代码,您能否解释一下您异步任务的想法? - gabba

0

我认为没有绕过这个问题的方法,因为它会遭受异步void的所有缺点(正如Peter Schneider评论中链接的Stephen Cleary文章所讨论的那样)

如果您找不到或编写有关异步API的同步版本,则最好的选择是调用异步方法,然后使用task.Wait()等待完成。如果您有多个异步调用,请使用ContinueWith组合它们。基本上,您需要使用.Net 4.0风格的Task库。


-1

部分类似于接口。 它们是一种契约。 实现部分类方法的任何人,就像实现接口方法一样,都在履行该契约。 在这种情况下,该方法的契约为同步方法。 没有办法进行异步实现,因为该方法的正确异步实现需要调用该方法的调用者知道它是一个异步方法,并相应地采取行动。 由于调用方将合同编写为同步方法,因此不会发生这种情况。

因此,您的解决方案是更改方法的合同以使其变为异步,即更改部分类方法的声明,或提供同步而不是异步实现。

我想第三个选项是让接口(在本例中为部分类)同时支持两者。 拥有两个部分类方法,一个异步的,一个同步的,让实现者提供他们想要的任何一个。


你能提供一个部分异步方法的例子吗?或者给我指点一些例子? - gabba
@gabba 它只需具有任何其他异步方法的签名。它将返回一个 Task,或在旧式编码中接受回调,或使用其他通知调用者已完成的方式。但现在通常只返回一个 Task - Servy
1
据我所知,部分类方法无法返回值。部分类方法必须是void类型。 - gabba
@gabba 那么它就必须接受回调或其他形式的异步操作作为参数传递,而不是由该方法返回。 - Servy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接