我正在尝试扩展一个框架,我们的框架用户可以使用 C# 作为具有非阻塞函数(又名“协程”)的语言。我的第一个设计使用yield return
语句和 IEnumerator 作为函数返回值。
但是,如果您尝试调用另一个产生函数(如果另一个函数应该返回一个值,则更是如此),这很容易出错并且使用起来很尴尬。
所以我在玩弄使用async
和await
提供 corountines 的想法。生成的语法会更有趣。
在我们的框架中,我需要确保这些非阻塞脚本中的任何一个都不会并行运行,因此我编写了自己的脚本来自行SynchonizationContext
安排所有操作。这就像一个魅力。
现在更有趣的东西:我们设计的另一个核心部分是,用户可以注册某种“检查功能”,如果它们失败,则不会继续“当前”执行功能。每次非阻塞功能恢复时都应执行检查功能。
例如:
async Task DoSomething()
{
var someObject = SomeService.Get(...);
using (var check = new SanityCheckScope())
{
check.StopWhen(() => someObject.Lifetime < 0);
...
await SomeOtherStuff();
// when execution comes back in here, the StopWhen - condition above should be
// evaluated and the Task should not be scheduled if its true.
...
}
}
每当SomeOtherStuff
或任何由它调用的异步函数恢复时,都应检查注册的条件,DoSomething
如果任何条件为真,则应停止。
为了实现这一点,我的 SynchronizationContext 检查已注册的函数(通过CallContext.LogicalSetData
),如果返回 true,则不安排任务。
现在来了棘手的问题。假设函数SomeOtherStuff
如下所示:
async Task SomeOtherStuff()
{
using (var check = new SanityCheckScope())
{
// register my own check functions
await Whatever();
}
}
在示例中SomeOtherStuff
注册了自己的检查功能。如果它们在 之后为真await Whatever()
,自然SomeOtherStuff
应该只停止该功能。(假设如果 SomeOtherStuff 返回 a Task<XXX>
,那么如果default(XXX)
将其用作返回值对我来说就可以了。)
我怎么能接近这个?我无法访问await SomeOtherStuff();
原始函数中的操作。任何一个的开头似乎都没有钩子或回调await
(无论如何也没有意义)。
另一个想法是抛出异常而不是“不调度”任务。相反(或附加于)using
-block,我会写一个 try/catch。但是,然后我遇到的问题是,如果内部的任何检查功能在 DoSomething
内部失败后await Whatever();
我将如何停止DoSomething
(连同SomeOtherStuff
)?
因此,在我从头开始所有这些并回到我的IEnumerator
和yield return
.. 之前,有人知道这是否可以由async
/await
框架完成吗?