Created
August 23, 2015 02:27
-
-
Save cchamberlain/7b1962d71dc379d82bb4 to your computer and use it in GitHub Desktop.
Generic extension methods for inlining the flow of try-catch-finally blocks. Contains separate implementations for value types and reference types and handles both sync and async.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public static class TryExtensions { | |
| /// <summary> | |
| /// Inline try-catch-finally block for return <typeparamref name="TResult"/> value types. The input is chained through the try, and optionally through the catch and finally blocks. By default, will not throw unless an exception is returned from any of the try-catch-finally blocks. | |
| /// </summary> | |
| /// <typeparam name="T">The type of the input to flow through try-catch-finally.</typeparam> | |
| /// <typeparam name="TResult">The type (value) of the try-catch-finally result.</typeparam> | |
| /// <param name="input">The <typeparamref name="T"/> input to be chained through the try-catch-finally blocks.</param> | |
| /// <param name="tryLogic">The try logic to execute. Receives <typeparamref name="T"/> input and returns <typeparamref name="TResult"/> result or any exception object which will subsequently be thrown.</param> | |
| /// <param name="catchLogic">The catch logic to execute. Runs only when try logic throws. Receives the exception and <typeparamref name="T"/> input. Returns <typeparamref name="TResult"/> result or any exception object which will subsequently be thrown.</param> | |
| /// <param name="finallyLogic">The finally logic to execute. Receives the resultant <typeparamref name="TResult"/> output from the try or catch logic and returns <typeparamref name="TResult"/> result or any exception which will subsequently be thrown.</param> | |
| /// <param name="throws">Whether unexpected exceptions should be thrown (default: false).</param> | |
| /// <returns>The <typeparamref name="TResult"/> result of flowing through the logic blocks or null.</returns> | |
| public static TResult? TryVal<T, TResult>(this T input, Func<T, dynamic> tryLogic, Func<Exception, T, dynamic> catchLogic = null, Func<T, TResult?, dynamic> finallyLogic = null, bool throws = false) where TResult : struct { | |
| TResult? result = null; | |
| try { | |
| result = ResolveValExceptions<TResult>(tryLogic?.Invoke(input)); | |
| } catch (Exception ex) { | |
| result = ResolveValExceptions<TResult>(catchLogic?.Invoke(ex, input), ex, throws); | |
| } finally { | |
| if (finallyLogic != null) result = ResolveValExceptions<TResult>(finallyLogic(input, result)); | |
| } | |
| return result; | |
| } | |
| /// <summary> | |
| /// Inline async try-catch-finally block for return <typeparamref name="TResult"/> value types. The input is chained through the try, and optionally through the catch and finally blocks. By default, will not throw unless an exception is returned from any of the try-catch-finally blocks. | |
| /// </summary> | |
| /// <typeparam name="T">The type of the input to flow through async try-catch-finally.</typeparam> | |
| /// <typeparam name="TResult">The type (value) of the async try-catch-finally result.</typeparam> | |
| /// <param name="input">The <typeparamref name="T"/> input to be chained through the async try-catch-finally blocks.</param> | |
| /// <param name="tryLogicAsync">The async try logic to execute. Receives <typeparamref name="T"/> input and returns <typeparamref name="TResult"/> result or any exception object which will subsequently be thrown.</param> | |
| /// <param name="catchLogicAsync">The async catch logic to execute. Runs only when try logic throws. Receives the exception and <typeparamref name="T"/> input. Returns <typeparamref name="TResult"/> result or any exception object which will subsequently be thrown.</param> | |
| /// <param name="finallyLogicAsync">The async finally logic to execute. Receives the resultant <typeparamref name="TResult"/> output from the try or catch logic and returns <typeparamref name="TResult"/> result or any exception which will subsequently be thrown.</param> | |
| /// <param name="throws">Whether unexpected exceptions should be thrown (default: false).</param> | |
| /// <returns>The <typeparamref name="TResult"/> result of flowing through the async logic blocks or null.</returns> | |
| public static async Task<TResult?> TryValAsync<T, TResult>(this T input, Func<T, Task<dynamic>> tryLogicAsync, Func<Exception, T, Task<dynamic>> catchLogicAsync = null, Func<T, TResult?, Task<dynamic>> finallyLogicAsync = null, bool throws = false) where TResult : struct { | |
| TResult? result = null; | |
| try { | |
| var task = tryLogicAsync?.Invoke(input); | |
| if (task != null) result = ResolveValExceptions<TResult>(await task); | |
| } catch (Exception ex) { | |
| var task = catchLogicAsync?.Invoke(ex, input); | |
| if (task != null) result = ResolveValExceptions<TResult>(await task, ex, throws); | |
| } finally { | |
| var task = finallyLogicAsync?.Invoke(input, result); | |
| if (task != null) result = ResolveValExceptions<TResult>(await task); | |
| } | |
| return result; | |
| } | |
| private static TResult? ResolveValExceptions<TResult>(dynamic input, Exception exception = null, bool throws = false) where TResult : struct { | |
| var thrown = input as Exception; | |
| if (throws && exception != null) throw (thrown == null ? exception : new AggregateException(thrown, exception)); | |
| if (thrown != null) throw thrown; | |
| return input as TResult?; | |
| } | |
| /// <summary> | |
| /// Inline try-catch-finally block for return <typeparamref name="TResult"/> reference types. The input is chained through the try, and optionally through the catch and finally blocks. By default, will not throw unless an exception is returned from any of the try-catch-finally blocks. | |
| /// </summary> | |
| /// <typeparam name="T">The type of the input to flow through try-catch-finally.</typeparam> | |
| /// <typeparam name="TResult">The type (reference) of the try-catch-finally result.</typeparam> | |
| /// <param name="input">The <typeparamref name="T"/> input to be chained through the try-catch-finally blocks.</param> | |
| /// <param name="tryLogic">The try logic to execute. Receives <typeparamref name="T"/> input and returns <typeparamref name="TResult"/> result or any exception object which will subsequently be thrown.</param> | |
| /// <param name="catchLogic">The catch logic to execute. Runs only when try logic throws. Receives the exception and <typeparamref name="T"/> input. Returns <typeparamref name="TResult"/> result or any exception object which will subsequently be thrown.</param> | |
| /// <param name="finallyLogic">The finally logic to execute. Receives the resultant <typeparamref name="TResult"/> output from the try or catch logic and returns <typeparamref name="TResult"/> result or any exception which will subsequently be thrown.</param> | |
| /// <param name="throws">Whether unexpected exceptions should be thrown (default: false).</param> | |
| /// <returns>The <typeparamref name="TResult"/> result of flowing through the logic blocks or null.</returns> | |
| public static TResult TryRef<T, TResult>(this T input, Func<T, dynamic> tryLogic, Func<Exception, T, dynamic> catchLogic = null, Func<T, TResult, dynamic> finallyLogic = null, bool throws = false) where TResult : class { | |
| TResult result = null; | |
| try { | |
| result = ResolveRefExceptions<TResult>(tryLogic?.Invoke(input)); | |
| } catch (Exception ex) { | |
| result = ResolveRefExceptions<TResult>(catchLogic?.Invoke(ex, input), ex, throws); | |
| } finally { | |
| if (finallyLogic != null) result = ResolveRefExceptions<TResult>(finallyLogic(input, result)); | |
| } | |
| return result; | |
| } | |
| /// <summary> | |
| /// Inline async try-catch-finally block for return <typeparamref name="TResult"/> reference types. The input is chained through the try, and optionally through the catch and finally blocks. By default, will not throw unless an exception is returned from any of the try-catch-finally blocks. | |
| /// </summary> | |
| /// <typeparam name="T">The type of the input to flow through async try-catch-finally.</typeparam> | |
| /// <typeparam name="TResult">The type (reference) of the async try-catch-finally result.</typeparam> | |
| /// <param name="input">The <typeparamref name="T"/> input to be chained through the async try-catch-finally blocks.</param> | |
| /// <param name="tryLogicAsync">The async try logic to execute. Receives <typeparamref name="T"/> input and returns <typeparamref name="TResult"/> result or any exception object which will subsequently be thrown.</param> | |
| /// <param name="catchLogicAsync">The async catch logic to execute. Runs only when try logic throws. Receives the exception and <typeparamref name="T"/> input. Returns <typeparamref name="TResult"/> result or any exception object which will subsequently be thrown.</param> | |
| /// <param name="finallyLogicAsync">The async finally logic to execute. Receives the resultant <typeparamref name="TResult"/> output from the try or catch logic and returns <typeparamref name="TResult"/> result or any exception which will subsequently be thrown.</param> | |
| /// <param name="throws">Whether unexpected exceptions should be thrown (default: false).</param> | |
| /// <returns>The <typeparamref name="TResult"/> result of flowing through the async logic blocks or null.</returns> | |
| public static async Task<TResult> TryRefAsync<T, TResult>(this T input, Func<T, Task<dynamic>> tryLogicAsync, Func<Exception, T, Task<dynamic>> catchLogicAsync = null, Func<T, TResult, Task<dynamic>> finallyLogicAsync = null, bool throws = false) where TResult : class { | |
| TResult result = null; | |
| try { | |
| var task = tryLogicAsync?.Invoke(input); | |
| if (task != null) result = ResolveRefExceptions<TResult>(await task); | |
| } catch (Exception ex) { | |
| var task = catchLogicAsync?.Invoke(ex, input); | |
| if (task != null) result = ResolveRefExceptions<TResult>(await task, ex, throws); | |
| } finally { | |
| var task = finallyLogicAsync?.Invoke(input, result); | |
| if (task != null) result = ResolveRefExceptions<TResult>(await task); | |
| } | |
| return result; | |
| } | |
| private static TResult ResolveRefExceptions<TResult>(dynamic input, Exception exception = null, bool throws = false) where TResult : class { | |
| var thrown = input as Exception; | |
| if (throws && exception != null) throw (thrown == null ? exception : new AggregateException(thrown, exception)); | |
| if (thrown != null) throw thrown; | |
| return input as TResult; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment