Skip to content

Instantly share code, notes, and snippets.

@Lachee
Last active July 22, 2024 05:54
Show Gist options
  • Save Lachee/df07eede31e62bd129b93e2f9ec408ca to your computer and use it in GitHub Desktop.
Save Lachee/df07eede31e62bd129b93e2f9ec408ca to your computer and use it in GitHub Desktop.
Proof of concept for returning errors instead of throwing.
using System;
using System.Runtime.CompilerServices;
using UnityEngine.Events;
namespace StopMission.Utilities
{
public readonly struct Result<TException>
where TException : Exception
{
public readonly TException Exception;
public readonly bool HasException;
public Result(TException error)
{
this.Exception = error;
this.HasException = true;
}
public static Result<Exception> From()
{
return new Result<Exception>();
}
public static implicit operator bool(Result<TException> result)
{
return !result.HasException;
}
public static implicit operator TException(Result<TException> result)
{
if (!result.HasException)
return null;
return result.Exception;
}
}
public readonly struct Result<TValue, TExeption>
where TExeption : Exception
{
public readonly TValue Value;
public readonly bool HasValue;
public readonly TExeption Exception;
public readonly bool HasException;
public Result(TValue value)
{
this.Value = value;
this.Exception = null;
this.HasValue = true;
this.HasException = false;
}
public Result(TExeption error)
{
this.Value = default;
this.Exception = error;
this.HasValue = false;
this.HasException = true;
}
public static Result<TValue, Exception> From(TValue result)
{
return new Result<TValue, Exception>(result);
}
public static implicit operator bool(Result<TValue, TExeption> result)
{
return !result.HasException;
}
public static implicit operator TExeption(Result<TValue, TExeption> result)
{
if (!result.HasException)
return null;
return result.Exception;
}
public static implicit operator TValue(Result<TValue, TExeption> result)
{
if (!result.HasValue)
throw new AggregateException("Result has an error instead of a value.", result.Exception);
return result.Value;
}
}
public static class Try
{
#region Result<Exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Result<Exception> Invoke(Action func)
{
return Invoke<Exception>(func);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Result<TError> Invoke<TError>(Action func)
where TError : Exception
{
try
{
func();
return new Result<TError>();
}
catch (TError error)
{
return new Result<TError>(error);
}
}
#endregion
#region Result<Value, Exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Result<TValue, Exception> Invoke<TValue>(Func<TValue> func)
{
return Invoke<TValue, Exception>(func);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Result<TValue, TError> Invoke<TValue, TError>(Func<TValue> func)
where TError : Exception
{
try
{
TValue value = func();
return new Result<TValue, TError>(value);
}
catch (TError error)
{
return new Result<TValue, TError>(error);
}
}
#endregion
}
public static class TryExtensions
{
public static Result<Exception> TryInvoke(this UnityEvent evt)
{
try
{
evt.Invoke();
return new Result<Exception>();
}
catch (Exception e) { return new Result<Exception>(e); }
}
public static Result<Exception> TryInvoke<T0>(this UnityEvent<T0> evt, T0 arg0)
{
try
{
evt.Invoke(arg0);
return new Result<Exception>();
}
catch (Exception e) { return new Result<Exception>(e); }
}
public static Result<Exception> TryInvoke<T0, T1>(this UnityEvent<T0, T1> evt, T0 arg0, T1 arg1)
{
try
{
evt.Invoke(arg0, arg1);
return new Result<Exception>();
}
catch (Exception e) { return new Result<Exception>(e); }
}
public static Result<Exception> TryInvoke<T0, T1, T2>(this UnityEvent<T0, T1, T2> evt, T0 arg0, T1 arg1, T2 arg2)
{
try
{
evt.Invoke(arg0, arg1, arg2);
return new Result<Exception>();
}
catch (Exception e) { return new Result<Exception>(e); }
}
public static Result<Exception> TryInvoke<T0, T1, T2, T3>(this UnityEvent<T0, T1, T2, T3> evt, T0 arg0, T1 arg1, T2 arg2, T3 arg3)
{
try
{
evt.Invoke(arg0, arg1, arg2, arg3);
return new Result<Exception>();
}
catch (Exception e) { return new Result<Exception>(e); }
}
}
}
@Lachee
Copy link
Author

Lachee commented Jul 22, 2024

the implicit casts might not be to everyones tastes. The idea of it throwing later is really awkward and a annoying work around to ensure safety. Probably better to actually remove them and make it all explicit like C#'s Nullable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment