2013-02-19 71 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); 
    } 
} 

請注意,如果您需要拋出多個異常,最終可能會產生更多問題 - 這取決於您的確切上下文。

相關問題