2013-02-19 49 views
0

我正在调用一个我没有的方法,它返回一个'Task'对象。我想从我的方法返回该对象,但我也需要重写该对象的Exception属性。如果底层任务捕获异常,并且我的用户通过异常属性检索异常,则需要调整它们在返回的异常中看到的数据。将TypeA的返回对象转换为TypeA派生的类型

我想知道是否有更好的解决方案来解决这个问题,而不是通过反射进行复制。我真的不想创建一个新的实例,但我找不到一种方法来避免它。

另一种可能性是将Task对象包装在我自己的类中。但是,那么我的方法将不会返回一个任务(或派生自)的对象,这可能会导致下游困难。更不用说执行Task的所有公共成员的代码量,除了调用基本版本之外什么都不做。

下面的代码不起作用,很明显,但在概念上它就是我想要做的:

public class MyTask : Task 
{ 
    override Exception Exception { get { return Tweak(base.Exception); } } 
} 

public MyTask MyMethod() 
{ 
    Task t = MethodIDontOwnThatReturnsTask(); 
    return (MyTask) t;  // Can I do this type of operation without copying t? 
} 

回答

2

与其试图改变现有任务或改变它的显示方式,只需创建一个新的Task(这就是ContinueWith将会执行的操作)。他们不是很贵:

public Task MyMethod() 
{ 
    return MethodIDontOwnThatReturnsTask() 
     .ContinueWith(t => { throw Tweak(t.Exception); } 
     , TaskContinuationOptions.OnlyOnFaulted); 
} 
+0

正是我需要知道的,没有!多谢你们! – ChrisInSeattle 2013-02-19 21:31:35

3

不,你不能一旦它被创建更改对象的类型。

我也不愿意通过反射进行复制。我会试图创建一个新的TaskCompletionSource,并从返回的任务中添加一个延续,以适当地在TaskCompletionSource上设置结果,并随时调整异常。

我有一些代码已经这样做了,在你实际上已经有了一个Task<T>的情况:

var tcs = new TaskCompletionSource<SomeResultType>(); 
task.ContinueWith(completed => 
{ 
    PropagateResult(completed, tcs); 
}, TaskContinuationOptions.ExecuteSynchronously); 
return tcs.Task; 
... 

// Generally useful method... 
private static void PropagateResult<T>(Task<T> completedTask, 
    TaskCompletionSource<T> completionSource) 
{ 
    switch (completedTask.Status) 
    { 
     case TaskStatus.Canceled: 
      completionSource.TrySetCanceled(); 
      break; 
     case TaskStatus.Faulted: 
      // This is the bit you'd want to tweak 
      completionSource.TrySetException(completedTask.Exception.InnerExceptions); 
      break; 
     case TaskStatus.RanToCompletion: 
      completionSource.TrySetResult(completedTask.Result); 
      break; 
     default: 
      throw new ArgumentException("Task was not completed"); 
    } 
} 

或者,如果您正在使用C#5你甚至可以只使用:

public async Task MyMethod() 
{ 
    Task t = MethodIDontOwnThatReturnsTask(); 
    try 
    { 
     await t; 
    } 
    catch(Exception e) 
    { 
     throw Tweak(e); 
    } 
} 

请注意,如果您需要抛出多个异常,最终可能会产生更多问题 - 这取决于您的确切上下文。

相关问题