Created
April 2, 2019 06:56
-
-
Save bessgeor/fbcbbc3e8e5de82fef8a2132c789b9ea to your computer and use it in GitHub Desktop.
Option<T> C#-way
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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