Skip to content

Instantly share code, notes, and snippets.

@bessgeor
Created April 2, 2019 06:56
Show Gist options
  • Save bessgeor/fbcbbc3e8e5de82fef8a2132c789b9ea to your computer and use it in GitHub Desktop.
Save bessgeor/fbcbbc3e8e5de82fef8a2132c789b9ea to your computer and use it in GitHub Desktop.
Option<T> C#-way
using System;
namespace PoorMansOption
{
public static class OptionExtensions
{
public static Option<T, T> Some<T>(T value)
where T : class
=> new Option<T, T>(value, true, _ => _);
public static Option<TDefaultable, T> None<TDefaultable, T>(Func<TDefaultable, T> accessor)
=> new Option<TDefaultable, T>(default, false, accessor);
public static Option<T?, T> Some<T>(T? value)
where T : struct
=> new Option<T?, T>(value, true, _ => _.Value);
public static Option<T, T> Option<T>(this T self)
where T : class
=> self != null ? Some(self) : None((T _) => _);
public static Option<T?, T> Option<T>(this T? self)
where T : struct
=> self.HasValue
? Some(self)
: None((T? _) => _.Value);
public static Option<TOut?, TOut> Apply<TIn, TOut>(this Option<TIn?, TIn> input, Func<TIn, TOut?> toApply)
where TIn : struct
where TOut : struct
=> input.HasValue
? Option(toApply(input.Value))
: None((TOut? _) => _.Value);
public static Option<TOut?, TOut> Apply<TIn, TOut>(this Option<TIn?, TIn> input, Func<TIn, TOut> toApply)
where TIn : struct
where TOut : struct
=> input.HasValue
? Some(new TOut?(toApply(input.Value)))
: None((TOut? _) => _.Value);
public static Option<TOut, TOut> ApplyRef<TIn, TOut>(this Option<TIn?, TIn> input, Func<TIn, TOut> toApply)
where TIn : struct
where TOut : class
=> input.HasValue
? Option(toApply(input.Value))
: None((TOut _) => _);
public static Option<TOut?, TOut> ApplyVal<TIn, TOut>(this Option<TIn, TIn> input, Func<TIn, TOut?> toApply)
where TIn : class
where TOut : struct
=> input.HasValue
? Option(toApply(input.Value))
: None((TOut? _) => _.Value);
public static Option<TOut?, TOut> ApplyVal<TIn, TOut>(this Option<TIn, TIn> input, Func<TIn, TOut> toApply)
where TIn : class
where TOut : struct
=> input.HasValue
? Some(new TOut?(toApply(input.Value)))
: None((TOut? _) => _.Value);
public static Option<TOut, TOut> Apply<TIn, TOut>(this Option<TIn, TIn> input, Func<TIn, TOut> toApply)
where TIn : class
where TOut : class
=> input.HasValue
? Option(toApply(input.Value))
: None((TOut _) => _);
public static T? ToNullable<T>(this Option<T?, T> input)
where T : struct
=> input.HasValue ? new T?() : input.Value;
public static T ToNullable<T>(this Option<T, T> input)
where T : class
=> input.HasValue ? null : input.Value;
}
public readonly struct Option<TDefaultable, T> : IEquatable<Option<TDefaultable, T>>
{
private readonly Func<TDefaultable, T> _valueAccessor;
private TDefaultable _value { get; }
public bool HasValue { get; }
public T Value => _valueAccessor(_value);
public Option(TDefaultable value, bool hasValue, Func<TDefaultable, T> valueAccessor) => (_value, HasValue, _valueAccessor) = (value, hasValue, valueAccessor);
public override int GetHashCode()
{
unchecked
{
const int prime = -1521134295;
var hash = 12345701;
hash = hash * prime + (_valueAccessor?.GetHashCode() ?? 0);
hash = hash * prime + (_value?.GetHashCode() ?? 0);
hash = hash * prime + HasValue.GetHashCode();
return hash;
}
}
public bool Equals(Option<TDefaultable, T> other) => System.Collections.Generic.EqualityComparer<Func<TDefaultable, T>>.Default.Equals(_valueAccessor, other._valueAccessor) && System.Collections.Generic.EqualityComparer<TDefaultable>.Default.Equals(_value, other._value) && System.Collections.Generic.EqualityComparer<bool>.Default.Equals(HasValue, other.HasValue);
public override bool Equals(object obj) => obj is Option<TDefaultable, T> other && Equals(other);
public static bool operator ==(Option<TDefaultable, T>x, Option<TDefaultable, T>y) => x.Equals(y);
public static bool operator !=(Option<TDefaultable, T>x, Option<TDefaultable, T>y) => !x.Equals(y);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment