Sic04/FrameworkLocal/UIClient/Caliburn.Micro/Core/RescueResultDecorator.cs

75 lines
3.2 KiB
C#

namespace Caliburn.Micro.Core {
using System;
/// <summary>
/// A result decorator which rescues errors from the decorated result by executing a rescue coroutine.
/// </summary>
/// <typeparam name="TException">The type of the exception we want to perform the rescue on</typeparam>
public class RescueResultDecorator<TException> : ResultDecoratorBase where TException : Exception {
static readonly ILog Log = LogManager.GetLog(typeof(RescueResultDecorator<>));
readonly bool cancelResult;
readonly Func<TException, IResult> coroutine;
/// <summary>
/// Initializes a new instance of the <see cref="RescueResultDecorator&lt;TException&gt;"/> class.
/// </summary>
/// <param name="result">The result to decorate.</param>
/// <param name="coroutine">The rescue coroutine.</param>
/// <param name="cancelResult">Set to true to cancel the result after executing rescue.</param>
public RescueResultDecorator(IResult result, Func<TException, IResult> coroutine, bool cancelResult = true) : base(result) {
if (coroutine == null)
throw new ArgumentNullException("coroutine");
this.coroutine = coroutine;
this.cancelResult = cancelResult;
}
/// <summary>
/// Called when the execution of the decorated result has completed.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="innerResult">The decorated result.</param>
/// <param name="args">The <see cref="ResultCompletionEventArgs" /> instance containing the event data.</param>
protected override void OnInnerResultCompleted(CoroutineExecutionContext context, IResult innerResult, ResultCompletionEventArgs args) {
var error = args.Error as TException;
if (error == null) {
OnCompleted(args);
}
else {
Log.Error(error);
Log.Info(string.Format("Executing coroutine because {0} threw an exception.", innerResult.GetType().Name));
Rescue(context, error);
}
}
void Rescue(CoroutineExecutionContext context, TException exception) {
IResult rescueResult;
try {
rescueResult = coroutine(exception);
}
catch (Exception ex) {
OnCompleted(new ResultCompletionEventArgs {Error = ex});
return;
}
try {
rescueResult.Completed += RescueCompleted;
IoC.BuildUp(rescueResult);
rescueResult.Execute(context);
}
catch (Exception ex) {
RescueCompleted(rescueResult, new ResultCompletionEventArgs {Error = ex});
}
}
void RescueCompleted(object sender, ResultCompletionEventArgs args) {
((IResult)sender).Completed -= RescueCompleted;
OnCompleted(new ResultCompletionEventArgs
{
Error = args.Error,
WasCancelled = (args.Error == null && (args.WasCancelled || cancelResult))
});
}
}
}