0

「タスク」オブジェクトを返す自分が所有していないメソッドを呼び出しています。メソッドからそのオブジェクトを返したいのですが、そのオブジェクトの Exception プロパティもオーバーライドする必要があります。基になるタスクが例外をキャッチし、ユーザーが Exception プロパティを介してその例外を取得した場合、返された例外で表示されるデータを微調整する必要があります。

リフレクションを介してコピーを行うよりも、この問題に対するより良い解決策があるかどうか疑問に思っています。新しいインスタンスを作成したくありませんが、それを回避する方法が見つかりません。

もう 1 つの可能性は、独自のクラスで 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?
}
4

2 に答える 2

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);
    }
}

複数の例外をスローする必要がある場合、これはより問題になる可能性があることに注意してください-正確なコンテキストによって異なります。

于 2013-02-19T19:28:48.167 に答える
2

既存のタスクを変更したり、表示方法を変更したりするのではなく、新しいタスクを作成するだけTaskです(これが実行されContinueWithます)。彼らは本当に高価ではありません:

public Task MyMethod()
{
    return MethodIDontOwnThatReturnsTask()
        .ContinueWith(t => { throw Tweak(t.Exception); }
        , TaskContinuationOptions.OnlyOnFaulted);
}
于 2013-02-19T19:28:58.980 に答える