实施返回任务的方法时合同协议书 [英] Contract agreement when implementing a method that returns a Task
问题描述
有没有MS最佳实践或合同约定执行,返回任务的问候抛出异常的方法时?这提出了编写单元测试的时候,我试图找出如果我要测试/处理这种情况(我承认,答案可能是防御性的编码,但我不希望这样的答案)。
即
-
方法必须返回一个任务,它应该包含抛出异常。
-
方法必须返回一个任务,除非该方法提供了无效的参数(如ArgumentException的)。
-
方法必须返回一个任务,除了当开发商去流氓和做他/她想要的东西(JK)。
任务Foo1Async(字符串ID){
如果(ID == NULL){
抛出新ArgumentNullException();
}
//做的东西
}
任务Foo2Async(字符串ID){
如果(ID == NULL){
无功源=新TaskCompletionSource<布尔>();
source.SetException(新ArgumentNullException());
返回source.Task;
}
//做的东西
}
任务栏(字符串ID){
//参数检查
如果(ID == NULL)抛出新ArgumentNullException(ID)
尝试{
返回this.SomeService.GetAsync(ID).ContinueWith(T => {
//检查故障状态在这里
//传递例外通过。
})
}赶上(例外前){
//这里处理更多的故障状态。
//防守code。
//返回任务有例外。
无功源=新TaskCompletionSource<布尔>();
source.SetException(前);
返回source.Task;
}
}
我问一个有些类似的问题最近:
<一个href="http://stackoverflow.com/questions/21055920/handling-exceptions-from-the-synchronous-part-of-async-method">Handling例外情况的异步方法同步的部分。
如果该方法有一个异步
签名,这并不重要,如果你从方法的同步或异步的一部分抛出关系。在这两种情况下,异常将被存储在工作
里面。唯一的区别是,所得到的任务
对象将立即在前者的情况下完成的(故障)。
如果该方法没有异步
签名时,可能会引发异常调用程序的堆栈帧。
IMO,在两种情况下,主叫方的不应该做出的异常是否已被抛出的同步或异步的一部分的任何假设或方法是否具有异步
签名,在所有。
如果你真的需要知道,如果任务已经完成同步,可以随时查询其 Task.Completed
/ 断陷
/ 取消
状态,或 Task.Exception
属性,而不等待:
尝试
{
变种任务= Foo1Async(ID);
//检查是否同步完成任何错误
//比OperationCanceledException其他
如果(task.IsFaulted)
{
//你有三个选择在这里:
// 1)检查task.Exception
// 2)再次引发与计谋,如果主叫方是异步方法
等待任务;
// 3)重新掷通过检查task.Result
//或调用task.Wait(),后者既用于工作&LT; T&GT;和任务
}
}
赶上(例外五)
{
//从Foo1Async同步部分处理异常,
如果它不具有//`async`签名
Debug.Print(e.ToString())
扔;
}
不过,通常你应该只等待
的结果
,不若照顾任务完成同步或异步,以及哪部分可能抛出。任何异常将被重新抛出在调用程序上下文:
尝试
{
VAR的结果=等待Foo1Async(ID);
}
赶上(例外前)
{
// 处理它
Debug.Print(ex.ToString());
}
这适用于单元测试过,只要异步
方法返回一个工作
(单元测试引擎不支持异步无效
方法,AFAIK,这是有道理的:没有工作
来保持跟踪和等待
)。
返回到code,我会这样说:
任务Foo1Async(字符串ID){
如果(ID == NULL){
抛出新ArgumentNullException();
}
//做的东西
}
任务Foo2Async(字符串ID){
如果(ID == NULL){
抛出新ArgumentNullException();
}
//做的东西
}
任务栏(字符串ID){
//参数检查
如果(ID == NULL)抛出新ArgumentNullException(ID)
返回this.SomeService.GetAsync(ID);
}
让 Foo1Async
, Foo2Async
,酒吧
处理的异常,而不是捕获和人工繁殖它们。
Is there a MS "best practice" or contract agreement when implementing a method that returns a Task in regards to throwing exceptions? This came up when writing unit tests and I was trying to figure out if I should to test/handle this condition (I recognize that the answer could be "defensive coding", but I don't want that to be the answer).
i.e.
Method must always return a Task, which should contain the thrown Exception.
Method must always return a Task, except when the method supplies invalid arguments (i.e. ArgumentException).
Method must always return a Task, except when the developer goes rogue and does what he/she wants (jk).
Task Foo1Async(string id){
if(id == null){
throw new ArgumentNullException();
}
// do stuff
}
Task Foo2Async(string id){
if(id == null){
var source = new TaskCompletionSource<bool>();
source.SetException(new ArgumentNullException());
return source.Task;
}
// do stuff
}
Task Bar(string id){
// argument checking
if(id == null) throw new ArgumentNullException("id")
try{
return this.SomeService.GetAsync(id).ContinueWith(t => {
// checking for Fault state here
// pass exception through.
})
}catch(Exception ex){
// handling more Fault state here.
// defensive code.
// return Task with Exception.
var source = new TaskCompletionSource<bool>();
source.SetException(ex);
return source.Task;
}
}
I've asked a somewhat similar question recently:
Handling exceptions from the synchronous part of async method.
If the method has an async
signature, it doesn't matter if you throw from the synchronous or asynchronous part of method. In both cases, the exception will be stored inside the Task
. The only difference is that the resulting Task
object will be instantly completed (faulted) in the former case.
If the method doesn't have async
signature, the exception may be thrown on the caller's stack frame.
IMO, in either case the caller should not make any assumption about whether the exception has been thrown from the synchronous or asynchronous part, or whether the method has async
signature, at all.
If you really need to know if the task has completed synchronously, you can always check its Task.Completed
/Faulted
/Cancelled
status, or Task.Exception
property, without awaiting:
try
{
var task = Foo1Async(id);
// check if completed synchronously with any error
// other than OperationCanceledException
if (task.IsFaulted)
{
// you have three options here:
// 1) Inspect task.Exception
// 2) re-throw with await, if the caller is an async method
await task;
// 3) re-throw by checking task.Result
// or calling task.Wait(), the latter works for both Task<T> and Task
}
}
catch (Exception e)
{
// handle exceptions from synchronous part of Foo1Async,
// if it doesn't have `async` signature
Debug.Print(e.ToString())
throw;
}
However, normally you should just await
the result
, without caring if the task has completed synchronously or asynchronously, and which part has possibly thrown. Any exception will be re-thrown on the caller context:
try
{
var result = await Foo1Async(id);
}
catch (Exception ex)
{
// handle it
Debug.Print(ex.ToString());
}
This works for unit testing too, as long as the async
method returns a Task
(the Unit Test engine doesn't support async void
method, AFAIK, which makes sense: there is no Task
to keep track of and await
).
Back to your code, I'd put it this way:
Task Foo1Async(string id){
if(id == null) {
throw new ArgumentNullException();
}
// do stuff
}
Task Foo2Async(string id) {
if(id == null){
throw new ArgumentNullException();
}
// do stuff
}
Task Bar(string id) {
// argument checking
if(id == null) throw new ArgumentNullException("id")
return this.SomeService.GetAsync(id);
}
Let the caller of Foo1Async
, Foo2Async
, Bar
deal with the exceptions, rather than capturing and propagating them manually.
这篇关于实施返回任务的方法时合同协议书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!