185 lines
4.0 KiB
C#
185 lines
4.0 KiB
C#
|
using System.Runtime.CompilerServices;
|
||
|
using static System.Runtime.CompilerServices.MethodImplOptions;
|
||
|
|
||
|
namespace InnovEnergy.Lib.Utils;
|
||
|
|
||
|
public static class ExceptionHandling
|
||
|
{
|
||
|
// TODO: https://blog.stephencleary.com/2020/06/a-new-pattern-for-exception-logging.html
|
||
|
|
||
|
public static Try<T> Try<T>(Func<T> func)
|
||
|
{
|
||
|
Object wrapped;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
wrapped = func()!;
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
wrapped = e;
|
||
|
}
|
||
|
|
||
|
return new Try<T>(wrapped);
|
||
|
}
|
||
|
|
||
|
|
||
|
public static async Task<Try<T>> Try<T>(Func<Task<T>> func)
|
||
|
{
|
||
|
Object wrapped;
|
||
|
|
||
|
try
|
||
|
{
|
||
|
wrapped = (await func())!;
|
||
|
}
|
||
|
catch (Exception e)
|
||
|
{
|
||
|
wrapped = e;
|
||
|
}
|
||
|
|
||
|
return new Try<T>(wrapped);
|
||
|
}
|
||
|
|
||
|
|
||
|
public static Try<R> ThenTry<T, R>(this Try<T> @try, Func<T, Try<R>> func)
|
||
|
{
|
||
|
var wrapped = @try.Wrapped;
|
||
|
|
||
|
if (wrapped is Exception e)
|
||
|
return new Try<R>(e);
|
||
|
|
||
|
return func((T) wrapped);
|
||
|
}
|
||
|
|
||
|
|
||
|
public static Try<R> ThenTry<T, R>(this Try<T> @try, Func<T, R> func)
|
||
|
{
|
||
|
var wrapped = @try.Wrapped;
|
||
|
|
||
|
if (wrapped is Exception e)
|
||
|
return new Try<R>(e);
|
||
|
|
||
|
return Try(() => func((T) wrapped));
|
||
|
}
|
||
|
|
||
|
|
||
|
public static Try<R> TryApply<T,R>(this T t, Func<T, R> func)
|
||
|
{
|
||
|
return Try(() => func(t));
|
||
|
}
|
||
|
|
||
|
[MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||
|
public static Try<R> TryApply<T1, T2, R>(this (T1 p1, T2 p2) t, Func<T1, T2, R> f)
|
||
|
{
|
||
|
return Try(() => f(t.p1, t.p2));
|
||
|
}
|
||
|
|
||
|
[MethodImpl(AggressiveInlining | AggressiveOptimization)]
|
||
|
public static Try<R> TryApply<T1, T2, T3, R>(this (T1 p1, T2 p2, T3 p3) t, Func<T1, T2, T3, R> f)
|
||
|
{
|
||
|
return Try(() => f(t.p1, t.p2, t.p3));
|
||
|
}
|
||
|
|
||
|
|
||
|
// public static Try<Boolean> Try(Action action)
|
||
|
// {
|
||
|
// Boolean Func()
|
||
|
// {
|
||
|
// action();
|
||
|
// return true;
|
||
|
// }
|
||
|
//
|
||
|
// return Try(Func);
|
||
|
// }
|
||
|
|
||
|
|
||
|
// public static Try<Boolean> TryApply<T>(this T t, Action<T> action)
|
||
|
// {
|
||
|
// return Try(() => action(t));
|
||
|
// }
|
||
|
|
||
|
|
||
|
public static Try<T> OnErrorDo<T>(this Try<T> @try, Action<Exception> onError)
|
||
|
{
|
||
|
if (@try.Wrapped is Exception originalException)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
onError(originalException);
|
||
|
}
|
||
|
catch (Exception handlerException) // make absolutely sure no exception can escape,
|
||
|
{ // even if the handler fails
|
||
|
const String msg = nameof(OnErrorDo) + " handler failed";
|
||
|
var ex = new AggregateException(msg, handlerException, originalException);
|
||
|
return new Try<T>(ex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return @try;
|
||
|
}
|
||
|
|
||
|
public static Try<T> OnErrorLog<T>(this Try<T> @try, String msg) // TODO: Func<String>
|
||
|
{
|
||
|
if (@try.Wrapped is Exception e)
|
||
|
return new Try<T>(new Exception(msg, e));
|
||
|
|
||
|
return @try;
|
||
|
}
|
||
|
|
||
|
public static T Catch<T>(this Try<T> @try, T onError)
|
||
|
{
|
||
|
var wrapped = @try.Wrapped;
|
||
|
|
||
|
if (wrapped is Exception)
|
||
|
return onError;
|
||
|
|
||
|
return (T) wrapped;
|
||
|
}
|
||
|
|
||
|
public static Try<T> Catch<T>(this Try<T> @try, Func<Exception, T> onError)
|
||
|
{
|
||
|
var wrapped = @try.Wrapped;
|
||
|
|
||
|
if (wrapped is Exception e)
|
||
|
return Try(() => onError(e));
|
||
|
|
||
|
return @try;
|
||
|
}
|
||
|
|
||
|
public static Boolean Succeeds(Action action)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
action();
|
||
|
return true;
|
||
|
}
|
||
|
catch
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public static Boolean Succeeds<T>(Func<T> func)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
func();
|
||
|
return true;
|
||
|
}
|
||
|
catch
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
public readonly struct Try<T> // phantom type
|
||
|
{
|
||
|
internal readonly Object Wrapped;
|
||
|
|
||
|
internal Try(Object wrapped)
|
||
|
{
|
||
|
Wrapped = wrapped;
|
||
|
}
|
||
|
}
|