Last active
August 29, 2015 14:01
-
-
Save tomtheisen/5d9bb3a3a18e4aa86853 to your computer and use it in GitHub Desktop.
using linq query syntax to create a maybe<t> structure that can help avoid null reference exceptions
This file contains hidden or 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
void Main() { | |
Console.WriteLine("Printing the seconds of 1/2/3"); | |
PrintSecondDifference("1/2/3"); | |
Console.WriteLine("Printing the seconds of null"); | |
PrintSecondDifference(null); | |
} | |
// print the rounded number of seconds between the passed date and now | |
// if, at any point, there is no intermediate result (null), | |
// the calculation safely short circuits to the end | |
void PrintSecondDifference(string mysteryDate) { | |
var totalSeconds = | |
from m in Maybe.Create(mysteryDate) | |
from date in DateTime.Parse(m) | |
from span in DateTime.Now - date | |
from duration in span.Duration() | |
from seconds in duration.TotalSeconds | |
select Math.Round(seconds); | |
totalSeconds.Apply(Console.WriteLine); | |
} | |
#region " maybe implementation " | |
static class Maybe { | |
public static Maybe<T> Create<T>(T arg) { | |
if(arg == null) return None<T>.Instance; | |
return new Just<T>(arg); | |
} | |
} | |
public abstract class Maybe<T> { | |
public abstract Maybe<U> Select<U>(Func<T, U> fn); | |
public abstract Maybe<V> SelectMany<U, V>(Func<T, U> fn, Func<T, U, V> projection); | |
public abstract bool HasValue { get; } | |
public abstract T GetValueOrDefault(T defaultValue = default(T)); | |
public static implicit operator T(Maybe<T> m) { | |
return m.GetValueOrDefault(); | |
} | |
public void Apply(Action<T> action) { | |
this.Select<object>(t => { | |
action(t); | |
return null; | |
}); | |
} | |
public void Apply<U>(Func<T, U> fn) { | |
this.Select(fn); | |
} | |
} | |
internal class None<T> : Maybe<T> { | |
public static readonly None<T> Instance = new None<T>(); | |
protected None() { } | |
override public Maybe<U> Select<U>(Func<T, U> fn) { | |
return None<U>.Instance; | |
} | |
override public Maybe<V> SelectMany<U, V>(Func<T, U> fn, Func<T, U, V> projection) { | |
return None<V>.Instance; | |
} | |
override public bool HasValue { | |
get { return false; } | |
} | |
override public T GetValueOrDefault(T defaultValue) { | |
return defaultValue; | |
} | |
override public string ToString() { | |
return "None"; | |
} | |
} | |
internal class Just<T> : Maybe<T> { | |
public readonly T Value; | |
public Just(T value) { | |
this.Value = value; | |
} | |
override public Maybe<U> Select<U>(Func<T, U> fn) { | |
return Maybe.Create<U>(fn(this.Value)); | |
} | |
override public Maybe<V> SelectMany<U, V>(Func<T, U> fn, Func<T, U, V> projection) { | |
return | |
from u in Maybe.Create<U>(fn(this.Value)) | |
select projection(this.Value, u); | |
} | |
override public bool HasValue { | |
get { return true; } | |
} | |
override public T GetValueOrDefault(T defaultValue) { | |
return this.Value; | |
} | |
public override string ToString() { | |
return this.Value.ToString(); | |
} | |
} | |
#endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment