Skip to content

Instantly share code, notes, and snippets.

@tomtheisen
Last active August 29, 2015 14:01
Show Gist options
  • Save tomtheisen/5d9bb3a3a18e4aa86853 to your computer and use it in GitHub Desktop.
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
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