Maybe there is more


Michel Perfetti, has taken my little Maybe thingie and gone a lot further,


by using expression tree re-writting he has made it possible to express this:


string code = licensePlate.Maybe(lp => lp.Car)
                          .Maybe(c => c.Owner)
                          .Maybe(o => o.Address)
                          .Maybe(a => a.PostCode);


which is NULL safe but very cumbersome like this:


string code = licensePlate.Maybe2(lp => lp.Car.Owner.Address.PostCode);


which is much cleaner and still NULL safe. 


Michel does this by declaring Maybe2 to take an Expression, rather than a Func i.e. it has this signature: public static V Maybe2<T, V>(this T t, Expression<Func<T, V>> expression)


Then he cracks open the expression and rewrites it to do each property access inside a call to Maybe.


Nice stuff Michel.


UPDATE: Sorry for originally getting your last name wrong Michel, and thanks Matthieu for pointing it out!

Comments (3)

  1. xiu@shoeke.com says:

    I just had to try this one step further 😛

       public static class Null

       {

           private static readonly MethodInfo maybeMethod;

           static Null()

           {

               maybeMethod = typeof(Null).GetMethod(“Maybe”, BindingFlags.Public | BindingFlags.Static);

           }

           public static V Maybe<T, V>(this T t, Func<T, V> selector) where T : class

           {

               return t != null ? selector(t) : default(V);

           }

           public static T Try<T>(Expression<Func<T>> ex)

           {

               MemberExpression memberBody = ex.Body as MemberExpression;

               if (memberBody != null)

               {

                   MethodCallExpression result = ConvertMemberToMethodCall(memberBody);

                   LambdaExpression lambda = Expression.Lambda(result);

                   return (T)lambda.Compile().DynamicInvoke();

               }

               throw new NotSupportedException();

           }

           private static MethodCallExpression ConvertMemberToMethodCall(MemberExpression memberExpression)

           {

               MemberExpression me = memberExpression.Expression as MemberExpression;

               Expression ex = me != null ? ConvertMemberToMethodCall(me) : memberExpression.Expression;

               Type type = null;

               PropertyInfo prop = memberExpression.Member as PropertyInfo;

               if (prop != null)

               {

                   type = prop.PropertyType;

               }

               else

               {

                   FieldInfo field = memberExpression.Member as FieldInfo;

                   if (field != null)

                   {

                       type = field.FieldType;

                   }

               }

               if (type == null)

               {

                   throw new NotImplementedException();

               }

               MethodInfo methodInfo = maybeMethod.MakeGenericMethod(new[] { memberExpression.Member.DeclaringType, type });

               ParameterExpression p = Expression.Parameter(memberExpression.Member.DeclaringType, “p”);

               LambdaExpression maybeLamba = Expression.Lambda(Expression.MakeMemberAccess(p, memberExpression.Member), new[] { p });

               return Expression.Call(null, methodInfo, new[] { ex, maybeLamba });

           }    

       }

    Which can be used as:

               string testString = “Test”;

               int length4 = Null.Try(() => testString.Length); // 4

               string nullString = null;

               int length0 = Null.Try(() => nullString.Length); // 0

  2. Alex D James says:

    @XIU,

    that is pretty cool. Nice work

    Alex