我有一个方法
public Task<Task> DoSomeWorkOnARemoteMachine()
,非常具有描述性,通过以下方式在远程计算机上执行某些工作:
我使用Task<Task>
的原因是因为第一个Task<>
用于排队消息;当在远程机器上完成工作时(即,当收到来自代理的消息时),内部Task
完成。远程代理在执行工作期间捕获的任何异常都将与完成消息一起传递,并在内部Task
完成时重新抛出。
要调用此方法,我使用:
await await DoSomeWorkOnARemoteMachine();
将等待消息排队以执行作业,以及完成作业并接收任何异常。但是,如果我对是否在远程代理上完成作业不感兴趣,我可以将其称为:
await DoSomeWorkOnARemoteMachine();
不会await
内部Task
。但是,内部Task
(从远程代理接收消息,并重新抛出异常)仍将在某个时刻执行。我觉得这有点浪费,当我没有await
得到结果时,我想避免执行它。
我的问题是:Task
是否有可能“知道”它是await
,如果不是,则执行,或者执行其他代码路径(例如空Task
身体)。
我确实意识到我可以实现其他替代方案,例如传递“fire and forget”标志,或者为“fire and forget”添加重载。如果我能在没有客户端API更改的情况下实现这一点,那就太棒了
涉及实现此类远程工作执行的其他项目的答案也很棒!
答案 0 :(得分:3)
这是一个非常有趣的问题。然而,如果我理解正确的话,我相信这是不可能的,就像你提出的那样,因为它没有意义(IMO)。让我们看看下面的模型(如果我弄错了,请告诉我):
static async Task<Task> DoSomeWorkOnARemoteMachine()
{
// Point X:
await Task.Delay(1000);
// Point Y:
Console.WriteLine("request sent");
var taskInner = Task.Delay(2000);
// Point A: here you want to know if there's an await at Point B
return taskInner;
}
static async Task Test()
{
var taskOuter = DoWorkAsync();
// Point Z:
await taskOuter;
// Point B:
await taskOuter.Result; // await taskInner
Console.WriteLine("request received");
}
在 A点,您想知道 B点是否有await
。但此时此刻, B点仍在未来,尚未发生。你需要一台时间机器:)
[更新] 以同样的方式,在点X ,你无法知道点Z 的await
,因为代码流尚未达到 Z 。
然而,当处于 Y 时,从理论上讲,您可能可以知道 Z 处的await
(仍然不是<强>乙强>)。虽然,我不知道技术上是否有可能掌握这些信息。
答案 1 :(得分:3)
我认为它不容易或无法有效实现(使用Task.GetAwaiter是一个坏主意,并且无法从您的函数内部访问,请参阅Noseratio的回答)。以下是替代解决方案:
解决方案n°1:Task
执行的功能参数
await DoSomeWorkOnARemoteMachine(false) //Indicates that DoSomeWork shouldn't be executed
解决方案n°2:明确的任务执行
Task t = await DoSomeWorkOnARemoteMachine() ;
t.Start(); // For example, if you want to execute the resulting Task.
// You can also dispatch it to an other thread, etc...
答案 2 :(得分:2)
我认为你这样做的方式令人困惑。根本不清楚Task<Task>
应该是什么意思。我要做的是让你的方法返回类似Task<Work>
的东西。然后,Work
类型将具有GetResultAsync()
之类的方法,该方法将返回表示远程计算机上工作执行的Task
。
这样,您的代码具有更清晰的含义,您还可以根据是否调用GetResultAsync()
轻松识别是否处理响应。