Skip to content

Instantly share code, notes, and snippets.

@markrendle
Created October 18, 2011 11:25
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save markrendle/1295201 to your computer and use it in GitHub Desktop.
Save markrendle/1295201 to your computer and use it in GitHub Desktop.
Maybe Monad in C#
namespace MaybeMonad
{
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
static class Monads
{
/// <summary>
/// Returns the value of an expression, or <c>default(T)</c> if any parts of the expression are <c>null</c>.
/// </summary>
/// <typeparam name="T">The type of the Expression</typeparam>
/// <param name="expression">A parameterless lambda representing the path to the value.</param>
/// <returns>The value of the expression, or <c>default(T)</c> if any parts of the expression are <c>null</c>.</returns>
public static T Maybe<T>(Expression<Func<T>> expression)
{
var value = Maybe(expression.Body);
if (value == null) return default(T);
return (T)value;
}
static object Maybe(Expression expression)
{
var constantExpression = expression as ConstantExpression;
if (constantExpression != null)
{
return constantExpression.Value;
}
var memberExpression = expression as MemberExpression;
if (memberExpression != null)
{
var memberValue = Maybe(memberExpression.Expression);
if (memberValue != null)
{
var member = memberExpression.Member;
return GetValue(member, memberValue);
}
}
return null;
}
private static object GetValue(MemberInfo member, object memberValue)
{
var propertyInfo = member as PropertyInfo;
if (propertyInfo != null) return propertyInfo.GetValue(memberValue, null);
var fieldInfo = member as FieldInfo;
if (fieldInfo != null) return fieldInfo.GetValue(memberValue);
return null;
}
}
internal class Program
{
private static void Main(string[] args)
{
foreach (var person in TestCases())
{
var postCode = Monads.Maybe(() => person.Address.PostCode);
Console.WriteLine(postCode ?? "NULL");
}
}
private static IEnumerable<Person> TestCases()
{
yield return null;
yield return new Person {Name = "Bob"};
yield return new Person {Name = "Bob", Address = new Address()};
yield return new Person {Name = "Bob", Address = new Address {PostCode = "SL4 1QP"}};
}
}
class Person
{
public string Name { get; set; }
public Address Address { get; set; }
}
class Address
{
public string PostCode { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment