Last active
September 6, 2023 08:50
-
-
Save AlexeyRaga/a92e1747cfbf27dd0bda4f5aef2df303 to your computer and use it in GitHub Desktop.
Maybe in C#
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
public readonly struct Option<T> : IEquatable<Option<T>> | |
{ | |
private readonly T? _value; | |
public bool HasValue { get; } | |
public T Value | |
{ | |
get | |
{ | |
if (!HasValue) throw new InvalidOperationException("Option does not have a value."); | |
return _value!; | |
} | |
} | |
private Option(T? value, bool hasValue) | |
{ | |
_value = value; | |
HasValue = hasValue; | |
} | |
public static Option<T> Some(T value) => new(value, true); | |
public static Option<T> None() => new(default, false); | |
public override bool Equals(object? obj) => obj is Option<T> other && Equals(other); | |
public override int GetHashCode() => HashCode.Combine(_value, HasValue); | |
public override string ToString() => HasValue ? $"Some({_value?.ToString()})" : "None"; | |
public bool Equals(Option<T> other) => | |
HasValue == other.HasValue && EqualityComparer<T?>.Default.Equals(_value, other._value); | |
public static bool operator ==(Option<T> left, Option<T> right) => left.Equals(right); | |
public static bool operator !=(Option<T> left, Option<T> right) => !(left == right); | |
} |
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
public static class Option | |
{ | |
public delegate bool OutFunc<in TSource, TResult>(TSource source, out TResult result); | |
public delegate bool OutFunc<in TSource, in TParam, TResult>(TSource source, TParam param, out TResult result); | |
public static Option<T> Some<T>(T value) => Option<T>.Some(value); | |
public static Option<T> None<T>() => Option<T>.None(); | |
public static T ValueOrDefault<T>(this Option<T> source, T defaultValue) => | |
source.HasValue ? source.Value : defaultValue; | |
public static T ValueOrDefault<T>(this Option<T> source, Func<T> defaultValue) => | |
source.HasValue ? source.Value : defaultValue(); | |
public static Option<TResult> | |
TryGetValue<TSource, TResult>(TSource source, OutFunc<TSource, TResult> tryGetValue) => | |
tryGetValue(source, out var result) ? Some(result) : None<TResult>(); | |
public static Option<TResult> TryGetValue<TSource, TParam, TResult>(TSource source, TParam param, | |
OutFunc<TSource, TParam, TResult> tryGetValue) => | |
tryGetValue(source, param, out var result) ? Some(result) : None<TResult>(); | |
public static Option<T> Some<T>(T? value) where T : struct | |
{ | |
if (!value.HasValue) throw new ArgumentNullException(nameof(value)); | |
return Option<T>.Some(value.Value); | |
} | |
public static Option<T> FromValue<T>(T? value) where T : class => value == null ? None<T>() : Some(value); | |
public static Option<T> FromValue<T>(T? value) where T : struct => value.HasValue ? Some(value.Value) : None<T>(); | |
} |
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
public static class OptionExtensions | |
{ | |
public static T? ToNullable<T>(this Option<T> value) where T : class => value.HasValue ? value.Value : null; | |
public static T? ToNullableStruct<T>(this Option<T> value) where T : struct => value.HasValue ? value.Value : null; | |
public static Option<TResult> TryGetValue<TSource, TResult>(this TSource source, | |
Option.OutFunc<TSource, TResult> tryGetValue) => | |
Option.TryGetValue(source, tryGetValue); | |
public static Option<TResult> TryGetValue<TSource, TParam, TResult>(this TSource source, TParam param, | |
Option.OutFunc<TSource, TParam, TResult> tryGetValue) => | |
Option.TryGetValue(source, param, tryGetValue); | |
public static Option<TResult> Select<TSource, TResult>( | |
this Option<TSource> source, | |
Func<TSource, TResult> transform) => | |
source switch | |
{ | |
{ HasValue: true } => Option.Some(transform(source.Value)), | |
_ => Option.None<TResult>() | |
}; | |
public static Option<TResult> SelectMany<TSource, TResult>( | |
this Option<TSource> source, | |
Func<TSource, Option<TResult>> transform) => | |
source switch | |
{ | |
{ HasValue: true } => transform(source.Value), | |
_ => Option.None<TResult>() | |
}; | |
public static Option<TResult> SelectMany<TSource, TCollection, TResult>( | |
this Option<TSource> source, | |
Func<TSource, Option<TCollection>> binder, | |
Func<TSource, TCollection, TResult> selector) => | |
source.SelectMany(src => binder(src).Select(x => selector(src, x))); | |
public static Option<T> Where<T>(this Option<T> source, Func<T, bool> predicate) => | |
source switch | |
{ | |
{ HasValue: true } when predicate(source.Value) => source, | |
_ => Option.None<T>() | |
}; | |
public static IEnumerable<T> Collect<T>(this IEnumerable<Option<T>> values) => | |
from value in values where value.HasValue select value.Value; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment