Created
June 20, 2018 20:58
-
-
Save mshwf/79294e2f35ec1005f43ef5557d95b9af to your computer and use it in GitHub Desktop.
Full optional type implementation
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
//credits to Zoran Horvat, author of Making Your C# Code More Object-oriented course. | |
namespace MakingYourCSharpCodeMoreObjectOriented | |
{ | |
public class Option<T> : IOption<T> | |
{ | |
private IEnumerable<T> Content { get; } | |
private Option(IEnumerable<T> content) | |
{ | |
Content = content; | |
} | |
public static Option<T> Some(T value) => | |
new Option<T>(new[] { value }); | |
public static Option<T> None() => | |
new Option<T>(new T[0]); | |
public IFiltered<T> When(Func<T, bool> predicate) | |
{ | |
return | |
Content | |
.Select(item => WhenSome(item, predicate)) | |
.DefaultIfEmpty(new NoneNotMatchedAsSome<T>()) | |
.Single(); | |
} | |
private IFiltered<T> WhenSome(T value, Func<T, bool> predicate) => | |
predicate(value) ? new SomeMatched<T>(value) : (IFiltered<T>)new SomeNotMatched<T>(value); | |
public IFiltered<T> WhenSome() | |
{ | |
return | |
Content | |
.Select<T, IFiltered<T>>(item => new SomeMatched<T>(item)) | |
.DefaultIfEmpty(new NoneNotMatchedAsSome<T>()) | |
.Single(); | |
} | |
public IFilteredNone<T> WhenNone() | |
{ | |
return | |
Content | |
.Select<T, IFilteredNone<T>>(item => new SomeNotMatchedAsNone<T>(item)) | |
.DefaultIfEmpty(new NoneMatched<T>()) | |
.Single(); | |
} | |
} | |
internal class NoneMatched<T> : IFilteredNone<T>, IFilteredNoneActionable<T> | |
{ | |
public IActionable<T> Do(Action action) => | |
new ActionResolved<T>(action); | |
public IMapped<T, TResult> MapTo<TResult>(Func<TResult> mapping) => | |
new MappingResolved<T, TResult>(mapping()); | |
} | |
internal class SomeNotMatchedAsNone<T> : IFilteredNone<T> | |
{ | |
private T Value { get; } | |
public SomeNotMatchedAsNone(T value) | |
{ | |
Value = value; | |
} | |
public IActionable<T> Do(Action action) => | |
new ActionOnSomeNotResolved<T>(Value); | |
public IMapped<T, TResult> MapTo<TResult>(Func<TResult> mapping) => | |
new MappingOnSomeNotResolved<T, TResult>(Value); | |
} | |
internal class NoneNotMatchedAsSome<T> : IFiltered<T> | |
{ | |
public IActionable<T> Do(Action<T> action) => | |
new ActionOnNoneNotResolved<T>(); | |
public IMapped<T, TResult> MapTo<TResult>(Func<T, TResult> mapping) => | |
new MappingOnNoneNotResolved<T, TResult>(); | |
} | |
internal class ActionOnNoneNotResolved<T> : IActionable<T> | |
{ | |
public IFilteredActionable<T> When(Func<T, bool> predicate) => | |
new NoneNotMatchedAsSome<T>(); | |
public IFilteredActionable<T> WhenSome() => | |
new NoneNotMatchedAsSome<T>(); | |
public IFilteredNoneActionable<T> WhenNone() => | |
new NoneMatched<T>(); | |
public void Execute() { } | |
} | |
internal class MappingOnNoneNotResolved<T, TResult> : IMapped<T, TResult> | |
{ | |
public IFilteredMapped<T, TResult> When(Func<T, bool> predicate) => | |
new NoneNotMatchedForMapping<T, TResult>(); | |
public IFilteredMapped<T, TResult> WhenSome() => | |
new NoneNotMatchedForMapping<T, TResult>(); | |
public IFilteredNoneMapped<T, TResult> WhenNone() => | |
new NoneMatchedForMapping<T, TResult>(); | |
public TResult Map() | |
{ | |
throw new InvalidOperationException(); | |
} | |
} | |
internal class NoneMatchedForMapping<T, TResult> : IFilteredNoneMapped<T, TResult> | |
{ | |
public IMapped<T, TResult> MapTo(Func<TResult> mapping) => | |
new MappingResolved<T, TResult>(mapping()); | |
} | |
internal class NoneNotMatchedForMapping<T, TResult> : IFilteredNoneMapped<T, TResult>, IFilteredMapped<T, TResult> | |
{ | |
public IMapped<T, TResult> MapTo(Func<TResult> mapping) => | |
new MappingOnNoneNotResolved<T, TResult>(); | |
public IMapped<T, TResult> MapTo(Func<T, TResult> mapping) => | |
new MappingOnNoneNotResolved<T, TResult>(); | |
} | |
internal class SomeNotMatched<T> : IFiltered<T>, IFilteredNoneActionable<T> | |
{ | |
private T Value; | |
public SomeNotMatched(T value) | |
{ | |
Value = value; | |
} | |
public IActionable<T> Do(Action<T> action) | |
{ | |
return new ActionOnSomeNotResolved<T>(Value); | |
} | |
public IActionable<T> Do(Action action) => | |
new ActionOnSomeNotResolved<T>(Value); | |
public IMapped<T, TResult> MapTo<TResult>(Func<T, TResult> mapping) | |
{ | |
return new MappingOnSomeNotResolved<T, TResult>(Value); | |
} | |
} | |
internal class MappingOnSomeNotResolved<T, TResult> : IMapped<T, TResult> | |
{ | |
private T Value { get; } | |
public MappingOnSomeNotResolved(T value) | |
{ | |
Value = value; | |
} | |
public IFilteredMapped<T, TResult> When(Func<T, bool> predicate) => | |
predicate(Value) | |
? (IFilteredMapped<T, TResult>)new SomeMatchedForMapping<T, TResult>(Value) | |
: new SomeNotMatchedForMapping<T, TResult>(Value); | |
public IFilteredMapped<T, TResult> WhenSome() => | |
new SomeMatchedForMapping<T, TResult>(Value); | |
public IFilteredNoneMapped<T, TResult> WhenNone() => | |
new SomeNotMatchedAsNoneForMapping<T, TResult>(Value); | |
public TResult Map() | |
{ | |
throw new InvalidOperationException(); | |
} | |
} | |
internal class SomeNotMatchedAsNoneForMapping<T, TResult> : IFilteredNoneMapped<T, TResult> | |
{ | |
private T Value { get; } | |
public SomeNotMatchedAsNoneForMapping(T value) | |
{ | |
Value = value; | |
} | |
public IMapped<T, TResult> MapTo(Func<TResult> mapping) => | |
new MappingOnSomeNotResolved<T, TResult>(Value); | |
} | |
internal class SomeMatchedForMapping<T, TResult> : IFilteredMapped<T, TResult> | |
{ | |
private T Value; | |
public SomeMatchedForMapping(T value) | |
{ | |
Value = value; | |
} | |
public IMapped<T, TResult> MapTo(Func<T, TResult> mapping) => | |
new MappingResolved<T, TResult>(mapping(Value)); | |
} | |
internal class SomeNotMatchedForMapping<T, TResult> : IFilteredMapped<T, TResult> | |
{ | |
private T Value; | |
public SomeNotMatchedForMapping(T value) | |
{ | |
Value = value; | |
} | |
public IMapped<T, TResult> MapTo(Func<T, TResult> mapping) => | |
new MappingOnSomeNotResolved<T, TResult>(Value); | |
} | |
internal class ActionOnSomeNotResolved<T> : IActionable<T> | |
{ | |
private T Value { get; } | |
public ActionOnSomeNotResolved(T value) | |
{ | |
Value = value; | |
} | |
public IFilteredActionable<T> When(Func<T, bool> predicate) => | |
predicate(Value) ? (IFilteredActionable<T>)new SomeMatched<T>(Value) : new SomeNotMatched<T>(Value); | |
public IFilteredActionable<T> WhenSome() => | |
new SomeMatched<T>(Value); | |
public IFilteredNoneActionable<T> WhenNone() => | |
new SomeNotMatched<T>(Value); | |
public void Execute() { } | |
} | |
internal class SomeMatched<T> : IFiltered<T> | |
{ | |
private T Value; | |
public SomeMatched(T value) | |
{ | |
Value = value; | |
} | |
public IActionable<T> Do(Action<T> action) | |
{ | |
return new ActionResolved<T>(() => action(Value)); | |
} | |
public IMapped<T, TResult> MapTo<TResult>(Func<T, TResult> mapping) | |
{ | |
return new MappingResolved<T, TResult>(mapping(Value)); | |
} | |
} | |
internal class MappingResolved<T, TResult> : IMapped<T, TResult>, IFilteredMapped<T, TResult>, IFilteredNoneMapped<T, TResult> | |
{ | |
private TResult Result { get; } | |
public MappingResolved(TResult result) | |
{ | |
Result = result; | |
} | |
public IFilteredMapped<T, TResult> When(Func<T, bool> predicate) => this; | |
public IFilteredMapped<T, TResult> WhenSome() => this; | |
public IFilteredNoneMapped<T, TResult> WhenNone() => this; | |
public IMapped<T, TResult> MapTo(Func<T, TResult> mapping) => this; | |
public IMapped<T, TResult> MapTo(Func<TResult> mapping) => this; | |
public TResult Map() => Result; | |
} | |
internal class ActionResolved<T> : IActionable<T>, IFilteredActionable<T>, IFilteredNoneActionable<T> | |
{ | |
private Action Action { get; } | |
public ActionResolved(Action action) | |
{ | |
Action = action; | |
} | |
public IFilteredActionable<T> When(Func<T, bool> predicate) => this; | |
public IFilteredActionable<T> WhenSome() => this; | |
public IFilteredNoneActionable<T> WhenNone() => this; | |
public IActionable<T> Do(Action<T> action) => this; | |
public IActionable<T> Do(Action action) => this; | |
public void Execute() => Action(); | |
} | |
public interface IFilteredNoneActionable<T> | |
{ | |
IActionable<T> Do(Action action); | |
} | |
public interface IOption<T> | |
{ | |
IFiltered<T> When(Func<T, bool> predicate); | |
IFiltered<T> WhenSome(); | |
IFilteredNone<T> WhenNone(); | |
} | |
public interface IFilteredNone<T> | |
{ | |
IActionable<T> Do(Action action); | |
IMapped<T, TResult> MapTo<TResult>(Func<TResult> mapping); | |
} | |
public interface IFiltered<T> : IFilteredActionable<T> | |
{ | |
IMapped<T, TResult> MapTo<TResult>(Func<T, TResult> mapping); | |
} | |
public interface IMapped<T, TResult> | |
{ | |
IFilteredMapped<T, TResult> When(Func<T, bool> predicate); | |
IFilteredMapped<T, TResult> WhenSome(); | |
IFilteredNoneMapped<T, TResult> WhenNone(); | |
TResult Map(); | |
} | |
public interface IFilteredNoneMapped<T, TResult> | |
{ | |
IMapped<T, TResult> MapTo(Func<TResult> mapping); | |
} | |
public interface IFilteredMapped<T, TResult> | |
{ | |
IMapped<T, TResult> MapTo(Func<T, TResult> mapping); | |
} | |
public interface IFilteredActionable<T> | |
{ | |
IActionable<T> Do(Action<T> action); | |
} | |
public interface IActionable<T> | |
{ | |
IFilteredActionable<T> When(Func<T, bool> predicate); | |
IFilteredActionable<T> WhenSome(); | |
IFilteredNoneActionable<T> WhenNone(); | |
void Execute(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment