Last active
March 17, 2016 16:16
-
-
Save mollyporph/ab88b643aa6711016883 to your computer and use it in GitHub Desktop.
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 class User | |
{ | |
public string Name {get;set;} | |
public string Email{get;set;} | |
public string PhoneNumber{get;set;} | |
} | |
public class Program | |
{ | |
public static void Main(string[] args){ | |
User user = new User{Name ="Otto", Email="[email protected]", PhoneNumber ="+4613371337" | |
var res = Result.From(user) | |
.Then(CapitalizeName) | |
.Then(ValidateEmail) | |
.Then(SaveUser) | |
.Then(EnsureUserUnderstandsTheDocumentation) | |
if(res.HasException){ | |
throw new Exception($"Validation failed for user {user.Name}",res.Exception); | |
} | |
} | |
} | |
} | |
//Only function that I cared to implement :P | |
public User CapitalizeName(User user)=> user.With(x => x.Name,x.Name.ToUpper()); | |
//Bogus methods that should actually do something :P | |
public User ValidateEmail(User user) => user; | |
public User SaveUser(User user) => user; | |
//Obviously the user never understands the documentation | |
public User EnsureUserUnderstandsTheDocumentation(User user) => {throw new DivisionByZeroException();return user;} | |
public User NotifySubscribers(User user)=> user; | |
public static T With<T, P>(this T self, Expression<Func<T, P>> selector, P newValue) | |
{ | |
var me = (MemberExpression)selector.Body; | |
var changedProp = (System.Reflection.PropertyInfo)me.Member; | |
var clone = Activator.CreateInstance<T>(); | |
foreach (var prop in typeof(T).GetProperties()) | |
prop.SetValue(clone, prop.GetValue(self)); | |
changedProp.SetValue(clone, newValue); | |
return clone; | |
} | |
public class Result<T> | |
{ | |
public bool HasException { get; private set; } | |
public Exception Exception { get; private set; } | |
public T Value { get; private set; } | |
public Result(T value) | |
{ | |
HasException = false; | |
Value = value; | |
} | |
public Result(Exception exception) | |
{ | |
HasException = true; | |
Exception = exception; | |
} | |
public Result(Func<T> getValue) | |
{ | |
try | |
{ | |
Value = getValue(); | |
HasException = false; | |
} | |
catch (Exception exc) | |
{ | |
Exception = exc; | |
HasException = true; | |
} | |
} | |
public override string ToString() | |
=> HasException ? Exception.GetType().Name : (Value != null ? Value.ToString() : "null"); | |
} | |
public static class Result | |
{ | |
public static Result<T> From<T>(T value) | |
{ | |
return value.Unit(); | |
} | |
public static Result<T> Execute<T>(Func<T> getValue) | |
{ | |
return getValue.Unit(); | |
} | |
} | |
public static class ResultMonadExtensions | |
{ | |
public static Result<T> Unit<T>(this T value) | |
{ | |
return new Result<T>(value); | |
} | |
public static Result<T> Unit<T>(this Func<T> getValue) | |
{ | |
return new Result<T>(getValue); | |
} | |
public static Result<U> Bind<T, U>(this Result<T> value, Func<T, Result<U>> k) | |
{ | |
return (value.HasException) | |
? new Result<U>(value.Exception) | |
: k(value.Value); | |
} | |
public static Result<V> SelectMany<T, U, V>(this Result<T> value, Func<T, Result<U>> k, Func<T, U, V> m) | |
{ | |
return value.Bind(t => k(t).Bind(u => m(t, u).Unit())); | |
} | |
} | |
public static class ResultExtensions | |
{ | |
public static Result<U> Then<T, U>(this Result<T> value, Func<T, U> getValue) | |
{ | |
return value.Bind(x => Result.Execute(() => getValue(x))); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment