diff --git a/Source/Scheduling/QueueOperation.Test.cs b/Source/Scheduling/QueueOperation.Test.cs
index 403c1f1..1f0da41 100644
--- a/Source/Scheduling/QueueOperation.Test.cs
+++ b/Source/Scheduling/QueueOperation.Test.cs
@@ -109,7 +109,7 @@ namespace Nuclex.Support.Scheduling {
/// Moves the operation into the ended state with an exception
/// Exception
public void SetEnded(Exception exception) {
- SetException(exception);
+ this.exception = exception;
OnAsyncEnded();
}
@@ -121,6 +121,18 @@ namespace Nuclex.Support.Scheduling {
OnAsyncProgressUpdated(progress);
}
+ ///
+ /// Allows the specific request implementation to re-throw an exception if
+ /// the background process finished unsuccessfully
+ ///
+ protected override void ReraiseExceptions() {
+ if(this.exception != null)
+ throw this.exception;
+ }
+
+ /// Exception that has occured in the background process
+ private volatile Exception exception;
+
}
#endregion // class TestOperation
diff --git a/Source/Scheduling/QueueOperation.cs b/Source/Scheduling/QueueOperation.cs
index 5b91eff..d810919 100644
--- a/Source/Scheduling/QueueOperation.cs
+++ b/Source/Scheduling/QueueOperation.cs
@@ -84,6 +84,15 @@ namespace Nuclex.Support.Scheduling {
startCurrentOperation();
}
+ ///
+ /// Allows the specific request implementation to re-throw an exception if
+ /// the background process finished unsuccessfully
+ ///
+ protected override void ReraiseExceptions() {
+ if(this.exception != null)
+ throw this.exception;
+ }
+
/// Prepares the current operation and calls its Begin() method
///
/// This subscribes the queue to the events of to the current operation
@@ -121,7 +130,7 @@ namespace Nuclex.Support.Scheduling {
OnAsyncProgressUpdated(this.completedWeight / this.totalWeight);
}
catch(Exception exception) {
- SetException(exception);
+ this.exception = exception;
}
}
@@ -135,7 +144,7 @@ namespace Nuclex.Support.Scheduling {
endCurrentOperation();
// Only jump to the next operation if no exception occured
- if(OccuredException == null) {
+ if(this.exception == null) {
++this.currentOperationIndex;
@@ -183,6 +192,8 @@ namespace Nuclex.Support.Scheduling {
private float completedWeight;
/// Index of the operation currently executing
private int currentOperationIndex;
+ /// Exception that has occured in the background process
+ private volatile Exception exception;
}
diff --git a/Source/Scheduling/ThreadOperation.cs b/Source/Scheduling/ThreadOperation.cs
index 0adac8d..22624b6 100644
--- a/Source/Scheduling/ThreadOperation.cs
+++ b/Source/Scheduling/ThreadOperation.cs
@@ -70,15 +70,26 @@ namespace Nuclex.Support.Scheduling {
Execute();
}
catch(Exception exception) {
- SetException(exception);
+ this.exception = exception;
}
finally {
OnAsyncEnded();
}
}
+ ///
+ /// Allows the specific request implementation to re-throw an exception if
+ /// the background process finished unsuccessfully
+ ///
+ protected override void ReraiseExceptions() {
+ if(this.exception != null)
+ throw this.exception;
+ }
+
/// Whether to use the ThreadPool for obtaining a background thread
private bool useThreadPool;
+ /// Exception that has occured in the background process
+ private volatile Exception exception;
}
diff --git a/Source/Tracking/Request.cs b/Source/Tracking/Request.cs
index 154eb4d..25d9d7d 100644
--- a/Source/Tracking/Request.cs
+++ b/Source/Tracking/Request.cs
@@ -37,7 +37,7 @@ namespace Nuclex.Support.Tracking {
/// OnAsyncEnded(), no matter what the outcome of your background operation is.
///
///
- public class Request : Progression {
+ public abstract class Request : Progression {
#region class EndedDummyRequest
@@ -48,21 +48,25 @@ namespace Nuclex.Support.Tracking {
/// Creates a new failed dummy request
/// Exception that caused the dummy to fail
public EndedDummyRequest(Exception exception) {
+ this.exception = exception;
OnAsyncEnded();
-
- // Only call SetException() if an actual exception was provided. Who knows what
- // evil code might be inside SetException() after all ;)
- if(exception != null)
- SetException(exception);
}
+ ///
+ /// Allows the specific request implementation to re-throw an exception if
+ /// the background process finished unsuccessfully
+ ///
+ protected override void ReraiseExceptions() {
+ if(this.exception != null)
+ throw this.exception;
+ }
+ /// Exception that supposedly caused the request to fail
+ private Exception exception;
}
#endregion // EndedDummyRequest
/// Creates a new failed dummy request
- ///
- /// Exception that supposedly caused the progression to fail
- ///
+ /// Exception that supposedly caused the request to fail
///
/// A failed request that reports the provided exception as cause for its failure
///
@@ -83,36 +87,76 @@ namespace Nuclex.Support.Tracking {
if(!Ended)
WaitHandle.WaitOne();
- // If an exception occured during the background execution
- if(this.occuredException != null)
- throw this.occuredException;
+ // Allow the implementor to throw an exception in case an error has occured
+ ReraiseExceptions();
}
- /// Exception that occured while the operation was executing
+ ///
+ /// Allows the specific request implementation to re-throw an exception if
+ /// the background process finished unsuccessfully
+ ///
+ protected virtual void ReraiseExceptions() {}
+
+ }
+
+ /// Request providing a result that can be passed to the caller
+ ///
+ /// Type of the result being provided by the request
+ ///
+ public abstract class Request : Request {
+
+ #region class EndedDummyRequest
+
+ /// Dummy request that is always in the ended state
+ private class EndedDummyRequest : Request {
+ /// Creates a new failed dummy request
+ /// Exception that caused the dummy to fail
+ public EndedDummyRequest(Exception exception) {
+ this.exception = exception;
+ OnAsyncEnded();
+ }
+ ///
+ /// Allows the specific request implementation to re-throw an exception if
+ /// the background process finished unsuccessfully
+ ///
+ protected override ResultType GatherResults() {
+ throw this.exception;
+ }
+ /// Exception that supposedly caused the request to fail
+ private Exception exception;
+ }
+
+ #endregion // EndedDummyRequest
+
+ /// Creates a new failed dummy request
+ /// Exception that supposedly caused the request to fail
+ ///
+ /// A failed request that reports the provided exception as cause for its failure
+ ///
+ public static new Request CreateFailedDummyRequest(Exception exception) {
+ return new EndedDummyRequest(exception);
+ }
+
+ /// Waits for the background operation to end
///
- /// If this field is null, it is assumed that no exception has occured
- /// in the background process. If it is set, however, the End() method will
- /// re-raise the exception to the calling thread when it is called.
+ /// Any exceptions raised in the background operation will be thrown
+ /// in this method. If you decide to override this method, you should
+ /// call End() first (and let any possible exception through to your
+ /// caller).
///
- public Exception OccuredException {
- get { return this.occuredException; }
+ public new ResultType Join() {
+ base.Join();
+
+ // Return the results of the request
+ return GatherResults();
}
- /// Sets the exception to raise to the caller of the End() method
- /// Exception to raise to the caller of the End() method
- protected void SetException(Exception exception) {
-
- // We allow the caller to set the exception multiple times. While I certainly
- // can't think of a scenario where this would happen, throwing an exception
- // in that case seems worse. The caller might just be executing an exception
- // handling block and locking + throwing here could cause all kinds of problems.
- this.occuredException = exception;
-
- }
-
- /// Exception that occured while the operation was executing
- private volatile Exception occuredException;
+ ///
+ /// Allows the specific request implementation to re-throw an exception if
+ /// the background process finished unsuccessfully
+ ///
+ protected abstract ResultType GatherResults();
}