Partager via


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

  • Anonymous
    March 03, 2008
    PingBack from http://msdnrss.thecoderblogs.com/2008/03/03/maybe-there-is-more/

  • Anonymous
    March 05, 2008
    I just had to try this one step further :P    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

  • Anonymous
    March 06, 2008
    @XIU,that is pretty cool. Nice workAlex