@@ -14,7 +14,7 @@ public enum TaskRunOptions
14
14
15
15
public interface ITask : IAsyncResult
16
16
{
17
- T Then < T > ( T continuation , TaskRunOptions runOptions = TaskRunOptions . OnSuccess ) where T : ITask ;
17
+ T Then < T > ( T continuation , TaskRunOptions runOptions = TaskRunOptions . OnSuccess , bool taskIsTopOfChain = false ) where T : ITask ;
18
18
ITask Catch ( Action < Exception > handler ) ;
19
19
ITask Catch ( Func < Exception , bool > handler ) ;
20
20
/// <summary>
@@ -24,7 +24,7 @@ public interface ITask : IAsyncResult
24
24
/// <summary>
25
25
/// Run a callback at the end of the task execution, on a separate thread, regardless of execution state
26
26
/// </summary>
27
- ITask Finally ( Action < bool , Exception > actionToContinueWith , TaskAffinity affinity ) ;
27
+ ITask Finally ( Action < bool , Exception > actionToContinueWith , TaskAffinity affinity = TaskAffinity . Concurrent ) ;
28
28
/// <summary>
29
29
/// Run another task at the end of the task execution, on a separate thread, regardless of execution state
30
30
/// </summary>
@@ -63,11 +63,11 @@ public interface ITask<TResult> : ITask
63
63
/// <summary>
64
64
/// Run a callback at the end of the task execution, on a separate thread, regardless of execution state
65
65
/// </summary>
66
- ITask < TResult > Finally ( Func < bool , Exception , TResult , TResult > continuation , TaskAffinity affinity ) ;
66
+ ITask < TResult > Finally ( Func < bool , Exception , TResult , TResult > continuation , TaskAffinity affinity = TaskAffinity . Concurrent ) ;
67
67
/// <summary>
68
68
/// Run a callback at the end of the task execution, on a separate thread, regardless of execution state
69
69
/// </summary>
70
- ITask Finally ( Action < bool , Exception , TResult > continuation , TaskAffinity affinity ) ;
70
+ ITask Finally ( Action < bool , Exception , TResult > continuation , TaskAffinity affinity = TaskAffinity . Concurrent ) ;
71
71
new ITask < TResult > Start ( ) ;
72
72
new ITask < TResult > Start ( TaskScheduler scheduler ) ;
73
73
new ITask < TResult > Progress ( Action < IProgress > progressHandler ) ;
@@ -93,6 +93,8 @@ public abstract class TaskBase : ITask
93
93
94
94
protected bool previousSuccess = true ;
95
95
protected Exception previousException ;
96
+ protected bool taskFailed = false ;
97
+ protected bool exceptionWasHandled = false ;
96
98
97
99
protected TaskBase continuationOnSuccess ;
98
100
protected TaskBase continuationOnFailure ;
@@ -147,14 +149,15 @@ protected TaskBase()
147
149
this . progress = new Progress { Task = this } ;
148
150
}
149
151
150
- public virtual T Then < T > ( T nextTask , TaskRunOptions runOptions = TaskRunOptions . OnSuccess )
152
+ public virtual T Then < T > ( T nextTask , TaskRunOptions runOptions = TaskRunOptions . OnSuccess , bool taskIsTopOfChain = false )
151
153
where T : ITask
152
154
{
153
155
Guard . ArgumentNotNull ( nextTask , nameof ( nextTask ) ) ;
154
156
var nextTaskBase = ( ( TaskBase ) ( object ) nextTask ) ;
155
157
156
158
// find the task at the top of the chain
157
- nextTaskBase = nextTaskBase . GetTopMostTask ( ) ?? nextTaskBase ;
159
+ if ( ! taskIsTopOfChain )
160
+ nextTaskBase = nextTaskBase . GetTopMostTask ( ) ?? nextTaskBase ;
158
161
// make the next task dependent on this one so it can get values from us
159
162
nextTaskBase . SetDependsOn ( this ) ;
160
163
@@ -176,7 +179,7 @@ public virtual T Then<T>(T nextTask, TaskRunOptions runOptions = TaskRunOptions.
176
179
else if ( runOptions == TaskRunOptions . OnFailure )
177
180
{
178
181
this . continuationOnFailure = nextTaskBase ;
179
- DependsOn ? . SetFaultHandler ( nextTaskBase ) ;
182
+ DependsOn ? . Then ( nextTaskBase , TaskRunOptions . OnFailure , true ) ;
180
183
}
181
184
else
182
185
{
@@ -270,16 +273,9 @@ public ITask Progress(Action<IProgress> handler)
270
273
271
274
public virtual ITask Start ( )
272
275
{
273
- var depends = GetTopMostTaskInCreatedState ( ) ;
274
- if ( depends != null )
275
- {
276
- depends . Run ( ) ;
277
- return this ;
278
- }
279
- else
280
- {
281
- return TaskManager . Instance . Schedule ( this ) ;
282
- }
276
+ var depends = GetTopMostTaskInCreatedState ( ) ?? this ;
277
+ depends . Run ( ) ;
278
+ return this ;
283
279
}
284
280
285
281
protected void Run ( )
@@ -288,10 +284,6 @@ protected void Run()
288
284
{
289
285
TaskManager . Instance . Schedule ( this ) ;
290
286
}
291
- else
292
- {
293
- RunContinuation ( ) ;
294
- }
295
287
}
296
288
297
289
/// <summary>
@@ -304,7 +296,7 @@ protected void Start(Task task)
304
296
previousSuccess = task . Status == TaskStatus . RanToCompletion && task . Status != TaskStatus . Faulted ;
305
297
previousException = task . Exception ;
306
298
Task . Start ( TaskManager . GetScheduler ( Affinity ) ) ;
307
- RunContinuation ( ) ;
299
+ SetContinuation ( ) ;
308
300
}
309
301
310
302
public virtual ITask Start ( TaskScheduler scheduler )
@@ -313,8 +305,8 @@ public virtual ITask Start(TaskScheduler scheduler)
313
305
{
314
306
//Logger.Trace($"Starting {Affinity} {ToString()}");
315
307
Task . Start ( scheduler ) ;
308
+ SetContinuation ( ) ;
316
309
}
317
- RunContinuation ( ) ;
318
310
return this ;
319
311
}
320
312
@@ -333,33 +325,22 @@ public bool IsChainExclusive()
333
325
return DependsOn ? . IsChainExclusive ( ) ?? false ;
334
326
}
335
327
336
- protected virtual void RunContinuation ( )
328
+ protected void SetContinuation ( )
337
329
{
338
- if ( continuationOnSuccess != null )
339
- {
340
- //Logger.Trace($"Setting ContinueWith {Affinity} {continuation}");
341
- Task . ContinueWith ( _ => ( ( TaskBase ) ( object ) continuationOnSuccess ) . Run ( ) , Token ,
342
- runOnSuccessOptions ,
343
- TaskManager . GetScheduler ( continuationOnSuccess . Affinity ) ) ;
344
- }
345
-
346
- if ( continuationOnFailure != null )
347
- {
348
- //Logger.Trace($"Setting ContinueWith {Affinity} {continuation}");
349
- Task . ContinueWith ( _ => ( ( TaskBase ) ( object ) continuationOnFailure ) . Run ( ) , Token ,
350
- runOnFaultOptions ,
351
- TaskManager . GetScheduler ( continuationOnFailure . Affinity ) ) ;
352
- }
353
-
354
330
if ( continuationOnAlways != null )
355
331
{
356
332
//Logger.Trace($"Setting ContinueWith {Affinity} {continuation}");
357
- Task . ContinueWith ( _ => ( ( TaskBase ) ( object ) continuationOnAlways ) . Run ( ) , Token ,
358
- runAlwaysOptions ,
359
- TaskManager . GetScheduler ( continuationOnAlways . Affinity ) ) ;
333
+ SetContinuation ( continuationOnAlways , runAlwaysOptions ) ;
360
334
}
361
335
}
362
336
337
+ protected void SetContinuation ( TaskBase continuation , TaskContinuationOptions runOptions )
338
+ {
339
+ Task . ContinueWith ( _ => ( ( TaskBase ) ( object ) continuation ) . Run ( ) , Token ,
340
+ runOptions ,
341
+ TaskManager . GetScheduler ( continuation . Affinity ) ) ;
342
+ }
343
+
363
344
protected ITask SetDependsOn ( ITask dependsOn )
364
345
{
365
346
DependsOn = ( TaskBase ) dependsOn ;
@@ -414,8 +395,20 @@ protected virtual void RaiseOnStart()
414
395
protected virtual void RaiseOnEnd ( )
415
396
{
416
397
OnEnd ? . Invoke ( this ) ;
417
- if ( continuationOnSuccess == null && continuationOnFailure == null && continuationOnAlways == null )
418
- CallFinallyHandler ( ) ;
398
+ if ( ! taskFailed || exceptionWasHandled )
399
+ {
400
+ if ( continuationOnSuccess == null && continuationOnAlways == null )
401
+ CallFinallyHandler ( ) ;
402
+ else if ( continuationOnSuccess != null )
403
+ SetContinuation ( continuationOnSuccess , runOnSuccessOptions ) ;
404
+ }
405
+ else
406
+ {
407
+ if ( continuationOnFailure == null && continuationOnAlways == null )
408
+ CallFinallyHandler ( ) ;
409
+ else if ( continuationOnFailure != null )
410
+ SetContinuation ( continuationOnFailure , runOnSuccessOptions ) ;
411
+ }
419
412
//Logger.Trace($"Finished {ToString()}");
420
413
}
421
414
@@ -426,16 +419,19 @@ protected void CallFinallyHandler()
426
419
427
420
protected virtual bool RaiseFaultHandlers ( Exception ex )
428
421
{
422
+ taskFailed = true ;
429
423
if ( catchHandler == null )
430
- return false ;
431
- bool handled = false ;
424
+ return continuationOnFailure != null ;
432
425
foreach ( var handler in catchHandler . GetInvocationList ( ) )
433
426
{
434
- handled |= ( bool ) handler . DynamicInvoke ( new object [ ] { ex } ) ;
435
- if ( handled )
427
+ if ( ( bool ) handler . DynamicInvoke ( new object [ ] { ex } ) )
428
+ {
429
+ exceptionWasHandled = true ;
436
430
break ;
431
+ }
437
432
}
438
- return handled ;
433
+ // if a catch handler returned true or we have a continuation for failure cases, don't throw
434
+ return exceptionWasHandled || continuationOnFailure != null ;
439
435
}
440
436
441
437
protected Exception GetThrownException ( )
@@ -527,9 +523,9 @@ protected TaskBase(Task<TResult> task)
527
523
} , task , Token , TaskCreationOptions . None ) ;
528
524
}
529
525
530
- public override T Then < T > ( T continuation , TaskRunOptions runOptions = TaskRunOptions . OnSuccess )
526
+ public override T Then < T > ( T continuation , TaskRunOptions runOptions = TaskRunOptions . OnSuccess , bool taskIsTopOfChain = false )
531
527
{
532
- return base . Then < T > ( continuation , runOptions ) ;
528
+ return base . Then < T > ( continuation , runOptions , taskIsTopOfChain ) ;
533
529
}
534
530
535
531
/// <summary>
@@ -635,6 +631,8 @@ protected virtual void RaiseOnEnd(TResult result)
635
631
finallyHandler ? . Invoke ( Task . Status == TaskStatus . RanToCompletion , result ) ;
636
632
CallFinallyHandler ( ) ;
637
633
}
634
+ else if ( continuationOnSuccess != null )
635
+ SetContinuation ( continuationOnSuccess , runOnSuccessOptions ) ;
638
636
//Logger.Trace($"Finished {ToString()} {result}");
639
637
}
640
638
0 commit comments