我正在开发一个包含RESTful Web服务的类库(供其他开发人员使用)。我正在使用HttpClient
命名空间中的System.Net.Http
类型来异步执行所有API调用。
除了简单地发送/接收内容之外,我还想对返回的XML数据进行额外的处理。无论你怎么说,这都涉及在类库中的某个地方使用Async / Await关键字。
我的问题是公开使用Async关键字的方法以及原因是否是好主意。我已经读过你应该将Async方法设为私有的地方,然后用一个return语句创建一个额外的方法。这就是我一直在做的事情,但感觉不对。
Public Function InvokeAsync(command As HttpRequestMessage) As Task(Of CommandResult)
Return InvokeAsyncInternal(command)
End Function
Private Async Function InvokeAsyncInternal(command As HttpRequestMessage) As Task(Of CommandResult)
Dim rawCommandResult As HttpResponseMessage = Await myHttpClient.SendAsync(command)
Dim finalResult As CommandResult = AdditionalProcessing(rawCommandResult)
Return finalResult
End Function
请记住,这是一个过于简化的代码示例:是否有任何好的参数不直接公开Async方法?
答案 0 :(得分:4)
这与编译器转换有关;您可以将“真正的”Async
方法与其Public
对应方式分开,并且获得与对迭代器(Yield
)方法执行相同类型分离时相同的好处。
特别是,从包装器抛出的异常处理方式与从Async
方法抛出的异常处理方式不同。当返回Async
的{{1}}方法抛出Task
时,它会被放置在返回的Exception
上,而不是直接抛向调用方。当Task
包装器方法(不是Public
)抛出Async
时,它会直接抛给调用者。
因此,前提条件式检查可以放在Exception
方法中。调用者可以忽略放在Public
上的异常,但是他们不能忽略直接抛出的异常。将前置条件异常置于Task
包装器中会强制调用者意识到它们正在滥用API,并且还允许将使用异常(直接抛出)与运行时异常(放在Public
上)分开)。
如果您的方法没有先决条件,那么您的Task
包装器只返回内部Public
。在这种情况下,Task
包装器是不必要的。
答案 1 :(得分:0)
考虑以下情况:
void Caller()
{
var t = AsyncThatThrows(null);
// ...
Task.WaitAny(t, t2); // <-- exception thrown here
}
Task AsyncThatThrows(Object o)
{
if (o == null)
throw new ArgumentNullException("o");
// ...
await // ...
// ...
}
请注意,在第一次等待之前会抛出异常,但只有在检查Task时才会重新抛出异常。是等待还是获得结果。如果您选择以下列方式实现它:
void Caller()
{
var t = AsyncThatThrows(null);// <-- exception thrown here
// ...
Task.WaitAny(t, t2);
}
Task AsyncThatThrows(Object o)
{
if (o == null)
throw new ArgumentNullException("o");
return AsyncThatThrows_Impl(o);
}
Task AsyncThatThrows_Impl(Object o)
{
// ...
await // ...
// ...
}
现在异常可以在其调用中捕获,您不必检查任务。在前一种情况下,即使我们还没有启动异步部分,但异常将存储在生成的Task中。