我正在调用一个我不拥有的方法,它返回一个'Task'对象。我想从我的方法返回该对象,但我还需要覆盖该对象的Exception属性。如果底层任务捕获异常,并且我的用户通过Exception属性检索该异常,我需要调整他们在返回的异常中看到的数据。
我想知道是否有更好的解决方案来解决这个问题,而不是通过反射进行复制。我真的不想创建一个新实例,但我找不到避免它的方法。
另一种可能性是将Task对象包装在我自己的类中。但是我的方法不会返回一个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?
}
答案 0 :(得分: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);
}
}
请注意,如果您需要抛出多个异常,最终可能会出现更多问题 - 这取决于您的具体情况。
答案 1 :(得分:2)
不是试图改变现有任务,也不改变其看法,只需创建一个新的Task
(ContinueWith
将会做什么)。它们并不贵:
public Task MyMethod()
{
return MethodIDontOwnThatReturnsTask()
.ContinueWith(t => { throw Tweak(t.Exception); }
, TaskContinuationOptions.OnlyOnFaulted);
}