Skip to content

Instantly share code, notes, and snippets.

@BoeseB
Last active February 25, 2016 14:54
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BoeseB/6c465bc8faaac5541449 to your computer and use it in GitHub Desktop.
Save BoeseB/6c465bc8faaac5541449 to your computer and use it in GitHub Desktop.
static class AsyncResultExtensions
{
//added to chain awaitable methods
public static async Task<Result<TResult>> OnSuccessAsync<T, TResult>(this Result<T> result, Func<T, Task<Result<TResult>>> func)
{
var res = result;
if (res.Failed)
return Result<TResult>.Fail(res.Error);
return await func(res.Value);
}
}
//Usage example
private async void DoSomething(string url)
{
(await OpcUrl.Create(url)
.OnSuccessAsync(address => InternalSearchEndpoints(address)))
.OnSuccess(list => UpdateEndpointList(list))
.OnFailure( error => _eventStream.Push(new DiscoveryError(error)));
}
public struct Result
{
private static readonly Result _ok = new Result(true, String.Empty);
private static readonly Result<Unit> _okUnit = Result<Unit>.Ok(Unit.Default);
public bool Succeeded { get; }
public string Error { get; }
public bool Failed
{
get { return !Succeeded; }
}
private Result( bool success, string error)
{
Contracts.Require(success || !string.IsNullOrEmpty(error));
Contracts.Require(!success || string.IsNullOrEmpty(error));
Succeeded = success;
Error = error;
}
public static implicit operator Result<Unit>(Result result)
{
if (result.Failed)
{
return Result<Unit>.Fail(result.Error);
}
return _okUnit;
}
public static Result Ok()
{
return _ok;
}
public static Result Fail(string message)
{
return new Result(false, message);
}
//Added for type inference so we can call Result.Ok(myvalue) without any type arguments
public static Result<T> Ok<T>(T value)
{
return Result<T>.Ok(value);
}
}
public struct Result<T>
{
public T Value { get; }
private Result([AllowNull] T value, bool success, string error)
{
Contracts.Require(success || !string.IsNullOrEmpty(error));
Contracts.Require(!success || string.IsNullOrEmpty(error));
Contracts.Require(value != null || !success);
Succeeded = success;
Error = error;
Value = value;
}
public bool Succeeded { get; }
public string Error { get; }
public bool Failed
{
get { return !Succeeded; }
}
public static Result<T> Fail(string message)
{
return new Result<T>(default(T), false, message);
}
public static Result<T> Ok(T value)
{
return new Result<T>(value, true, String.Empty);
}
public static Result Combine(params Result[] results)
{
foreach (Result result in results)
{
if (result.Failed)
return result;
}
return Result.Ok();
}
//To make Combine work with Result<T>
public static implicit operator Result(Result<T> result)
{
if (result.Failed)
{
return Result.Fail(result.Error);
}
return Result.Ok();
}
}
public static class ResultExtensions
{
public static Result OnSuccess(this Result result, Func<Result> func)
{
if (result.Failed)
return result;
return func();
}
public static Result OnSuccess<T>(this Result<T> result, Func<T, Result> func)
{
if(result.Failed) {
return Result.Fail(result.Error);
}
return func(result.Value);
}
public static Result OnSuccess(this Result result, Action action)
{
if (result.Failed)
return result;
action();
return Result.Ok();
}
public static Result OnSuccess<T>(this Result<T> result, Action<T> action)
{
if (result.Failed)
return Result.Fail(result.Error);
action(result.Value);
return Result.Ok();
}
public static Result<T> OnSuccess<T>(this Result result, Func<T> func)
{
if (result.Failed)
return Result<T>.Fail(result.Error);
return Result<T>.Ok(func());
}
public static Result<T> OnSuccess<T>(this Result result, Func<Result<T>> func)
{
if (result.Failed)
return Result<T>.Fail(result.Error);
return func();
}
public static Result<TResult> OnSuccess<T, TResult>(this Result<T> result, Func<T, Result<TResult>> func)
{
if (result.Failed)
return Result<TResult>.Fail(result.Error);
return func(result.Value);
}
public static Result OnFailure(this Result result, Action<string> action)
{
if (result.Failed)
{
action(result.Error);
}
return result;
}
public static Result OnBoth(this Result result, Action<Result> action)
{
action(result);
return result;
}
public static T OnBoth<T>(this Result result, Func<Result, T> func)
{
return func(result);
}
}
public struct Unit : IEquatable<Unit>
{
public static readonly Unit Default = new Unit();
public override int GetHashCode() =>
0;
public override bool Equals(object obj) =>
obj is Unit;
public override string ToString() =>
"()";
public bool Equals(Unit other) =>
true;
public static bool operator ==(Unit lhs, Unit rhs) =>
true;
public static bool operator !=(Unit lhs, Unit rhs) =>
false;
/// <summary>
/// Provide an alternative value to unit
/// </summary>
/// <typeparam name="T">Alternative value type</typeparam>
/// <param name="anything">Alternative value</param>
/// <returns>Alternative value</returns>
public T Return<T>(T anything) => anything;
/// <summary>
/// Provide an alternative value to unit
/// </summary>
/// <typeparam name="T">Alternative value type</typeparam>
/// <param name="anything">Alternative value</param>
/// <returns>Alternative value</returns>
public T Return<T>(Func<T> anything) => anything();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment