A game framework written with osu! in mind.
at master 3.0 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using System.Reflection; 6using System.Runtime.ExceptionServices; 7 8namespace osu.Framework.Extensions.ExceptionExtensions 9{ 10 public static class ExceptionExtensions 11 { 12 /// <summary> 13 /// Rethrows <paramref name="exception"/> as if it was captured in the current context. 14 /// This preserves the stack trace of <paramref name="exception"/>, and will not include the point of rethrow. 15 /// </summary> 16 /// <param name="exception">The captured exception.</param> 17 public static void Rethrow(this Exception exception) 18 { 19 ExceptionDispatchInfo.Capture(exception).Throw(); 20 } 21 22 /// <summary> 23 /// Rethrows the <see cref="Exception.InnerException"/> of an <see cref="AggregateException"/> if it exists, 24 /// otherwise, rethrows <paramref name="aggregateException"/>. 25 /// This preserves the stack trace of the exception that is rethrown, and will not include the point of rethrow. 26 /// </summary> 27 /// <param name="aggregateException">The captured exception.</param> 28 public static void RethrowAsSingular(this AggregateException aggregateException) => aggregateException.AsSingular().Rethrow(); 29 30 /// <summary> 31 /// Flattens <paramref name="aggregateException"/> into a singular <see cref="Exception"/> if the <paramref name="aggregateException"/> 32 /// contains only a single <see cref="Exception"/>. Otherwise, returns <paramref name="aggregateException"/>. 33 /// </summary> 34 /// <param name="aggregateException">The captured exception.</param> 35 /// <returns>The highest level of flattening possible.</returns> 36 public static Exception AsSingular(this AggregateException aggregateException) 37 { 38 if (aggregateException.InnerExceptions.Count != 1) 39 return aggregateException; 40 41 while (aggregateException.InnerExceptions.Count == 1) 42 { 43 if (!(aggregateException.InnerException is AggregateException innerAggregate)) 44 return aggregateException.InnerException; 45 46 aggregateException = innerAggregate; 47 } 48 49 return aggregateException; 50 } 51 52 /// <summary> 53 /// Retrieves the last exception from a recursive <see cref="TargetInvocationException"/>. 54 /// </summary> 55 /// <param name="exception">The exception to retrieve the exception from.</param> 56 /// <returns>The exception at the point of invocation.</returns> 57 public static Exception GetLastInvocation(this TargetInvocationException exception) 58 { 59 var inner = exception.InnerException; 60 while (inner is TargetInvocationException) 61 inner = inner.InnerException; 62 return inner; 63 } 64 } 65}